Keydown 事件触发 classList.remove 如果连续按下太多次按键将不起作用
Keydown event triggering classList.remove doesn't work if the key is pressed too many times in a row
我已经实现了 Wes Bos 的 Javascript 30 课程的架子鼓 (https://www.youtube.com/watch?v=VuN8qwZoego),但有些地方很奇怪。
当按下一个键时,我添加一个 class 和 key.classList.add('playing')
,它将键的 div 转换为 border-color: yellow
,除此之外,然后删除class 再次 this.classList.remove('playing');
一旦被 transitionend
事件触发。
它工作正常,直到我尝试非常快地多次按下某个键。然后,最终 .playing
class "sticks" 到 div,即不再删除。
window.addEventListener('keydown', (e) => {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);
if (!audio) return; //stop the function from running
audio.currentTime = 0;
audio.play();
key.classList.add('playing');
});
function removeTransition(e){
if (e.propertyName !== 'transform'){
return;
}
this.classList.remove('playing');
}
const keys = document.querySelectorAll('.key');
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
.drum-keys{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
margin-top: 100px;
padding: 0;
}
.key{
display: flex;
height: 70px;
width: 60px;
background-color: rgb(0,0,0, .2);
font-style: bold;
margin: 1em;
border: 2px solid lightgrey;
flex-direction: column;
transition: 0.09s;
text-align: center;
}
.key h1 {
font-size: 1.7em;
margin-top: 10px;
margin-bottom: 0;
}
.key p {
font-size: 0.7em;
margin-top: 5px;
}
.drum-keys li{
list-style-type: none;
}
.playing{
border-color: yellow;
box-shadow: 0 0 10px grey;
transform: scale(1.1);
}
<main class="site-content">
<div class="playground-main">
<ul class="drum-keys">
<li>
<div data-key="65" class="key"><h1>A</h1><p>CLAP</p></div>
</li>
<li>
<div data-key="83" class="key"><h1>S</h1><p>HIHAT</p></div>
</li>
<li>
<div data-key="68" class="key"><h1>D</h1><p>KICK</p></div>
</li>
<li>
<div data-key="70" class="key"><h1>F</h1><p>OPENHAT</p></div>
</li>
<li>
<div data-key="71" class="key"><h1>G</h1><p>BOOM</p></div>
</li>
<li>
<div data-key="72" class="key"><h1>H</h1><p>RIDE</p></div>
</li>
<li>
<div data-key="74" class="key"><h1>J</h1><p>SNARE</p></div>
</li>
<li>
<div data-key="75" class="key"><h1>K</h1><p>TOM</p></div>
</li>
<li>
<div data-key="76" class="key"><h1>L</h1><p>TINK</p></div>
</li>
</ul>
</div>
问题出在您对 keydown 动作的竞标,如果您按住它,它会比 transitionend 触发多次。因为它发生了多次,你最终得到 class 'playing' 并且没有发生转换,因此 'transitionend' 事件不再被触发。
将 keyup 更改为 keydown,应该没问题。
如果你像这样在控制台登录这两个函数并观察控制台,你可以很容易地看到这一点
window.addEventListener('keyup', (e) => {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);
/* if (!audio) return; //stop the function from running
*//* audio.currentTime = 0;
audio.play(); */
key.classList.add('playing');
console.log('keydown');
});
function removeTransition(e){
if (e.propertyName !== 'transform'){
return;
}
this.classList.remove('playing');
console.log('transition end');
}
const keys = document.querySelectorAll('.key');
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
如果您真的热衷于使用 'keydown',我认为您可以使用
key.classList.toggle('playing')
我已经实现了 Wes Bos 的 Javascript 30 课程的架子鼓 (https://www.youtube.com/watch?v=VuN8qwZoego),但有些地方很奇怪。
当按下一个键时,我添加一个 class 和 key.classList.add('playing')
,它将键的 div 转换为 border-color: yellow
,除此之外,然后删除class 再次 this.classList.remove('playing');
一旦被 transitionend
事件触发。
它工作正常,直到我尝试非常快地多次按下某个键。然后,最终 .playing
class "sticks" 到 div,即不再删除。
window.addEventListener('keydown', (e) => {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);
if (!audio) return; //stop the function from running
audio.currentTime = 0;
audio.play();
key.classList.add('playing');
});
function removeTransition(e){
if (e.propertyName !== 'transform'){
return;
}
this.classList.remove('playing');
}
const keys = document.querySelectorAll('.key');
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
.drum-keys{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
margin-top: 100px;
padding: 0;
}
.key{
display: flex;
height: 70px;
width: 60px;
background-color: rgb(0,0,0, .2);
font-style: bold;
margin: 1em;
border: 2px solid lightgrey;
flex-direction: column;
transition: 0.09s;
text-align: center;
}
.key h1 {
font-size: 1.7em;
margin-top: 10px;
margin-bottom: 0;
}
.key p {
font-size: 0.7em;
margin-top: 5px;
}
.drum-keys li{
list-style-type: none;
}
.playing{
border-color: yellow;
box-shadow: 0 0 10px grey;
transform: scale(1.1);
}
<main class="site-content">
<div class="playground-main">
<ul class="drum-keys">
<li>
<div data-key="65" class="key"><h1>A</h1><p>CLAP</p></div>
</li>
<li>
<div data-key="83" class="key"><h1>S</h1><p>HIHAT</p></div>
</li>
<li>
<div data-key="68" class="key"><h1>D</h1><p>KICK</p></div>
</li>
<li>
<div data-key="70" class="key"><h1>F</h1><p>OPENHAT</p></div>
</li>
<li>
<div data-key="71" class="key"><h1>G</h1><p>BOOM</p></div>
</li>
<li>
<div data-key="72" class="key"><h1>H</h1><p>RIDE</p></div>
</li>
<li>
<div data-key="74" class="key"><h1>J</h1><p>SNARE</p></div>
</li>
<li>
<div data-key="75" class="key"><h1>K</h1><p>TOM</p></div>
</li>
<li>
<div data-key="76" class="key"><h1>L</h1><p>TINK</p></div>
</li>
</ul>
</div>
问题出在您对 keydown 动作的竞标,如果您按住它,它会比 transitionend 触发多次。因为它发生了多次,你最终得到 class 'playing' 并且没有发生转换,因此 'transitionend' 事件不再被触发。
将 keyup 更改为 keydown,应该没问题。
如果你像这样在控制台登录这两个函数并观察控制台,你可以很容易地看到这一点
window.addEventListener('keyup', (e) => {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);
/* if (!audio) return; //stop the function from running
*//* audio.currentTime = 0;
audio.play(); */
key.classList.add('playing');
console.log('keydown');
});
function removeTransition(e){
if (e.propertyName !== 'transform'){
return;
}
this.classList.remove('playing');
console.log('transition end');
}
const keys = document.querySelectorAll('.key');
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
如果您真的热衷于使用 'keydown',我认为您可以使用
key.classList.toggle('playing')