如何在 if、else 条件下正确使用 event.code 和 event.button?

问题描述

我的目标是使用 vanilla Javascript 构建演奏鼓,当我仅使用 keydown 事件时,整个代码运行良好,不幸的是,我的鼓也必须通过鼠标“单击”才能播放。 当我将 "|| event.button == aKey == 0" 这部分添加到我的条件时,它仍然播放,但每个键上只有一个声音。所以我认为我的情况有问题。

而且,如果有可能以某种方式降低我的代码的可重复性,我将不胜感激。

const aKey = document.getElementById("A-key");
const sKey = document.getElementById("S-key");
const dKey = document.getElementById("D-key");
const fKey = document.getElementById("F-key");
const gKey = document.getElementById("G-key");
const hKey = document.getElementById("H-key");
const jKey = document.getElementById("J-key");
const kKey = document.getElementById("K-key");
const lKey = document.getElementById("L-key");

const playFunction = (event) => {
    if (event.code == "KeyA" || event.button == aKey == 0) {
        // 
        let audioA = document.createElement("AUdio");
        if (audioA.canPlayType("audio/wav")) {
            audioA.setAttribute("src","sounds/boom.wav");
        }
        audioA.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioA);

    } else if (event.code == "KeyS" || event.button == sKey == 0 ) {

        let audioS= document.createElement("AUdio");
        if (audioS.canPlayType("audio/wav")) {
            audioS.setAttribute("src","sounds/clap.wav");
        }
        audioS.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioS);

    } else if (event.code == "KeyD" || event.button == dKey == 0) {

        let audioD = document.createElement("AUdio");
        if (audioD.canPlayType("audio/wav")) {
            audioD.setAttribute("src","sounds/hihat.wav");
        }
        audioD.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioD);

    } else if (event.code == "KeyF"  || event.button == fKey == 0) {
        let audioF = document.createElement("AUdio");
        if (audioF.canPlayType("audio/wav")) {
            audioF.setAttribute("src","sounds/kick.wav");
        }
        audioF.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioF);

    } else if (event.code == "KeyG" || event.button == gKey == 0) {
        let audioG = document.createElement("AUdio");
        if (audioG.canPlayType("audio/wav")) {
            audioG.setAttribute("src","sounds/openhat.wav");
        }
        audioG.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioG);

    } else if (event.code == "KeyH" || event.button == hKey == 0) {
        let audioH = document.createElement("AUdio");
        if (audioH.canPlayType("audio/wav")) {
            audioH.setAttribute("src","sounds/ride.wav");
        }
        audioH.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioH);

    } else if (event.code == "KeyJ" || event.button == jKey == 0) {
        let audioJ = document.createElement("AUdio");
        if (audioJ.canPlayType("audio/wav")) {
            audioJ.setAttribute("src","sounds/snare.wav");
        }
        audioJ.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioJ);

    } else if (event.code == "KeyK" || event.button == kKey == 0) {
        let audioK = document.createElement("AUdio");
        if (audioK.canPlayType("audio/wav")) {
            audioK.setAttribute("src","sounds/tink.wav");
        }
        audioK.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioK);

    } else if (event.code == "KeyL" || event.button == lKey == 0) {
        let audioL = document.createElement("AUdio");
        if (audioL.canPlayType("audio/wav")) {
            audioL.setAttribute("src","sounds/tom.wav");
        }
        audioL.setAttribute("autoplay","autoplay");
        document.body.appendChild(audioL);
    } else {
        console.log("Try to use specified keys.")
    }
};

window.addEventListener('keydown',playFunction,false);
window.addEventListener('click',false);

解决方法

event.button == kKey == 0 没有多大意义。这类似于 (foo == bar) == baz,即测试第一个条件,然后根据另一个条件检查其结果(真或假)。如果要测试多个条件,请在每个条件之间使用 ||&&。此外,请始终使用 === 以避免出现意外的转换行为。

至于重构请求,只要您有一堆仅基于可参数化值(例如按钮文本或声音)而不同的分支,请使用数据结构(例如数组或对象)和索引/键。

具体来说,这里您只需要键 -> 音频或音频 URL 对,因此对象似乎很合适。

一旦您有了这样的结构,您就可以利用循环的力量来DRY 输出您的代码。

我没有您的音频文件或标记,因此您可以尝试将此概念证明应用于您的项目:

const baseURL = `https://upload.wikimedia.org/wikipedia/commons/`;
const sounds = {
  a: `7/7c/Bombo_Leg%C3%BCero_Grave.ogg`,s: `7/7f/Bombo_Ac%C3%BAstico.ogg`,d: `3/35/Bongo_Agudo.ogg`,f: `4/44/Bongo_Grave.ogg`,g: `b/b4/Sting.ogg`,// ... add more key-sound URL pairs ...
};

Object.keys(sounds).forEach(key => {
  const btn = document.createElement("button");
  document.querySelector("#drum-pad").appendChild(btn);
  const sound = new Audio(baseURL + sounds[key]);
  sounds[key] = sound;
  btn.textContent = key;
  btn.addEventListener("click",e => {
    sound.currentTime = 0;
    sound.play();
  });
});

document.addEventListener("keydown",e => {
  if (sounds[e.key]) {
    sounds[e.key].currentTime = 0;
    sounds[e.key].play();
  }
});
<div id="drum-pad"></div>