问题描述
我正在尝试构建一个鼓垫应用程序,并且大部分已经完成,除了我在按键时遇到的问题。我已经设置为当您按下某些键时,会显示特定文本并播放特定声音。这与鼠标点击完美配合,但是当我尝试使用键盘按钮时,它只显示文本,并给我这个错误:
不允许启动 AudioContext。它必须在页面上的用户手势之后恢复(或创建)。 @howler.js:2500
我正在使用以 Howler 作为依赖项的 useSound 钩子,这可能存在问题,但我不确定。这是文档的链接:https://github.com/joshwcomeau/use-sound
这是一个代码沙盒构建:https://codesandbox.io/s/drum-pad-jc9b5?file=/src/drumPad.css
完整代码如下:
useEffect(() =>{document.addEventListener("keydown",key)},[]
)
function key(e) {
// This runs the playThis() function when the desired keys are pressed,but the sound doesn't play.
let i = 0
let keycodes = drumBank.map(function(y,x){
if (y.keyTrigger === e.key) {
i = x
playThis(i)
}})
}
const [powerOn,setPowerOn] = useState(true)
const [text,setText] = useState("");
const [Sound0] = useSound(drumBank[0].url)
const [Sound1] = useSound(drumBank[1].url)
const [Sound2] = useSound(drumBank[2].url)
const [Sound3] = useSound(drumBank[3].url)
const [Sound4] = useSound(drumBank[4].url)
const [Sound5] = useSound(drumBank[5].url)
const [Sound6] = useSound(drumBank[6].url)
const [Sound7] = useSound(drumBank[7].url)
const [Sound8] = useSound(drumBank[8].url)
function playThis(num) {
if (powerOn === true)
{ setText(drumBank[num].id)
switch(num) {
case 0: Sound0()
break;
case 1: Sound1()
break;
case 2: Sound2()
break;
case 3: Sound3()
break;
case 4: Sound4()
break;
case 5: Sound5()
break;
case 6: Sound6()
break;
case 7: Sound7()
break;
case 8: Sound8()
break;
}
}
else {setText("Power is off")}
}
return (
<div id="drum-machine" className="drumpad-container" >
<h3 id={powerOn ? "drum-power-text-on" : "drum-power-text-off"}>Power: </h3>
<div id="drum-power-div" onClick={() => setPowerOn(!powerOn)}>
<div id={powerOn ? "drum-power-button-on" : "drum-power-button-off"}>
</div>
</div>
<div id="display" className="drumpad-display">
<p className="drumpad-text">{text}</p>
</div>
<button className="drum-pad" id="drum-pad-1" onClick={() => playThis(0)} >Q</button>
<button className="drum-pad" id="drum-pad-2" onClick={() => playThis(1)}>W</button>
<button className="drum-pad" id="drum-pad-3" onClick={() => playThis(2)}>E</button>
<button className="drum-pad" id="drum-pad-4" onClick={() => playThis(3)}>A</button>
<button className="drum-pad" id="drum-pad-5" onClick={() => playThis(4)}>S</button>
<button className="drum-pad" id="drum-pad-6" onClick={() => playThis(5)}>D</button>
<button className="drum-pad" id="drum-pad-7" onClick={() => playThis(6)}>Z</button>
<button className="drum-pad" id="drum-pad-8" onClick={() => playThis(7)}>X</button>
<button className="drum-pad" id="drum-pad-9" onClick={() => playThis(8)}>C</button>
</div>
)
}
key 函数也以某种方式绕过了我的电源功能,即使在电源关闭时应该停用 playThis() 也会显示文本。
如果有人能帮我弄清楚如何在按键上播放声音,我将不胜感激。
解决方法
我想通了。如果将 useSound 钩子放在函数内部,则它会在按键时正常播放声音,然后调用该函数而不是钩子本身。所以,不要把这些放在 playThis() 中:
const [Sound0] = useSound(drumBank[0].url)
const [Sound1] = useSound(drumBank[1].url)
const [Sound2] = useSound(drumBank[2].url)
const [Sound3] = useSound(drumBank[3].url)
const [Sound4] = useSound(drumBank[4].url)
const [Sound5] = useSound(drumBank[5].url)
const [Sound6] = useSound(drumBank[6].url)
const [Sound7] = useSound(drumBank[7].url)
const [Sound8] = useSound(drumBank[8].url)
我将这些常量放入它们各自的函数中,如下所示:
const [Sound0] = useSound(drumBank[0].url)
const [Sound1] = useSound(drumBank[1].url)
const [Sound2] = useSound(drumBank[2].url)
const [Sound3] = useSound(drumBank[3].url)
const [Sound4] = useSound(drumBank[4].url)
const [Sound5] = useSound(drumBank[5].url)
const [Sound6] = useSound(drumBank[6].url)
const [Sound7] = useSound(drumBank[7].url)
const [Sound8] = useSound(drumBank[8].url)
let audio0 = () => {sound0()}
let audio1 = () => {sound1()}
let audio2 = () => {sound2()}
let audio3 = () => {sound3()}
let audio4 = () => {sound4()}
let audio5 = () => {sound5()}
let audio6 = () => {sound6()}
let audio7 = () => {sound7()}
let audio8 = () => {sound8()}
然后在我的 playThis() 函数中,我将 audio0() 而不是 sound0(),然后它就可以工作了。像这样:
function playThis(num) {
if (powerOn === true)
{ setText(drumBank[num].id)
switch(num) {
case 0: audio0()
break;
case 1: audio1()
break;
case 2: audio2()
break;
case 3: audio3()
break;
case 4: audio4()
break;
case 5: audio5()
break;
case 6: audio6()
break;
case 7: audio7()
break;
case 8: audio8()
break;
}
}
else {setText("Power is off")}
}
至于绕过电源按钮的按键,我只使用了一个 useKeyPress 插件,而且效果很好。