实现效果
实现思路
-
一共要实现两个功能:
-
按下键盘
A-L
的某一个键就播放对应的音频-
实现这个功能需要监听键盘按下的事件,用到
onkeydown
事件- 可以在控制台打印一下
window
,会看到他里面自带了很多的事件(以on开头)
- 可以在控制台打印一下
-
要实现按下按键
A
,然后对应的方块A
就播放音频,就需要给每一个方块绑定按键A-L
对应的编号-
比如,给方块
A
添加onkeydown
事件后,打印一下event
,可以看到event
对象里有一个keyCode
属性,这个属性对应的按键A
的值为65
- 专门查按键对应的
keyCode
的网站:JavaScript Event keyCodes
- 专门查按键对应的
-
可以把这个
65
通过html的自定义属性data-*
绑定到方块A
上,这样在获取元素的时候直接通过event.keyCode
获取到对应的元素 -
获取到对应的音频元素后,使用
play()
方法播放音频-
这里需要注意,当按下了
A-L
以外的按键时,得到的audio
是为空的,会报错,所以需要进行判断,为空的话就直接return,结束掉这个onkeydown
事件函数,不在往下执行 -
这里还有一个问题就是,当我们连续按下通过一个按键时,他并不是每次都从头开始播放的,而是等上一下播放结束,所以音频播放的次数,跟按键按下的次数是不相等的。可以手动将
Audio
对象的currentTime
属性设置为0,实现每次按下按键都从头开始播放音频- 执行一下
console.log([audio]);
,可以看到他里面包含currentTime
这个属性
currentTime
属性设置或返回视频播放的当前位置(以秒计),当设置该属性时,播放会跳跃到指定的位置。
- 执行一下
<div data-key="65" id="clap" class="btn"> <kbd>A</kbd> <span>CLAP</span> </div> <audio data-key="65" src="sounds/clap.wav"></audio>
window.addEventListener('keydown', function(event){ var audio = document.querySelector(`audio[data-key="${event.keyCode}"]`); var btn = document.querySelector(`div[data-key="${event.keyCode}"]`); // console.log([audio]); // 如果按下的是其他的键,就直接return if (!audio) return; audio.currentTime = 0; audio.play(); })
-
-
-
-
按下按键后会有一个边框样式变化的特效,而且是一闪而过的
-
当按下按键时,就给对应的方块添加类名
playing
,从而实现边框样式的变化.playing { transform:scale(1.1); border-color:#ffc600; box-shadow: 0 0 10px #ffc600; }
-
样式一闪而过的效果:
-
给每一个方块添加
transition
属性,实现从样式a到样式b变化过渡 -
对这个过渡的过程进行监听,使用
transitionend
事件,在过渡完成后就删除类名playing
,从而移除样式 -
在
transitionend
事件函数里打印一下event,会看到他监听了方块上所有的属性,这是因为我设置的transition
值为all .07s ease;
,all
就代表方块设置的所有样式属性 -
但是我们只需要监听到
transform
属性,所以使用event.propertyName
过滤掉其他的属性事件
//获取元素 // 使用`Array.from()`将类数组转换为数组 var btns = Array.from(document.querySelectorAll('.btn')); btns.forEach(item => item.addEventListener('transitionend', function(event){ if (event.propertyName !== 'transform') return; // 过滤其中一种事件 event.target.classList.remove('playing') }));
-
-
-
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DrumKit</title>
<style>
*,html,body{
padding: 0;
margin: 0;
height: 100%;
}
#main{
width: 100%;
height: 100%;
display: flex;
justify-content: space-evenly;
align-items: center;
}
kbd{
height: auto;
font-size: 2.125rem;
font-weight: 700;
}
span{
height: auto;
display: block;
font-size: 0.75rem;
color: #ffc600;
margin-top: 4px;
}
.btn{
width: 100px;
height: 100px;
text-align: center;
border: 6px solid #333;
border-radius: 6px;
box-sizing: border-box;
padding: 12px;
cursor: pointer;
transition:all .07s ease;
}
audio{
display: none;
}
.playing {
transform:scale(1.1);
border-color:#ffc600;
box-shadow: 0 0 10px #ffc600;
}
</style>
</head>
<body>
<div id="main">
<div data-key="65" id="clap" class="btn">
<kbd>A</kbd>
<span>CLAP</span>
</div>
<div data-key="83" id="hihat" class="btn">
<kbd>S</kbd>
<span>HIHAT</span>
</div>
<div data-key="68" id="kick" class="btn">
<kbd>D</kbd>
<span>KICK</span>
</div>
<div data-key="70" id="openhat" class="btn">
<kbd>F</kbd>
<span>OPENHAT</span>
</div>
<div data-key="71" id="boom" class="btn">
<kbd>G</kbd>
<span>BOOM</span>
</div>
<div data-key="72" id="ride" class="btn">
<kbd>H</kbd>
<span>RIDE</span>
</div>
<div data-key="74" id="snare" class="btn">
<kbd>J</kbd>
<span>SNARE</span>
</div>
<div data-key="75" id="tom" class="btn">
<kbd>K</kbd>
<span>TOM</span>
</div>
<div data-key="76" id="tink" class="btn">
<kbd>L</kbd>
<span>TINK</span>
</div>
</div>
<audio data-key="65" src="sounds/clap.wav"></audio>
<audio data-key="83" src="sounds/hihat.wav"></audio>
<audio data-key="68" src="sounds/kick.wav"></audio>
<audio data-key="70" src="sounds/openhat.wav"></audio>
<audio data-key="71" src="sounds/boom.wav"></audio>
<audio data-key="72" src="sounds/ride.wav"></audio>
<audio data-key="74" src="sounds/snare.wav"></audio>
<audio data-key="75" src="sounds/tom.wav"></audio>
<audio data-key="76" src="sounds/tink.wav"></audio>
<script>
// 按照目标要求,我们要实现按下按键A-L对应的方块就能发出对应的声音
// 那么代码就需要实现两个部分
// 1. 按下按键音频能够播放 --> 解决怎么知道按下A要播放那个音频? -->
// 解决办法:按下按键触发事件,那必然用到`onkeydown`键盘事件,这个事件有一个属性`keyCode`记录着每一个按键对应的编码
// 将这个编码绑定到音频标签上(使用HTML自定义属性`data-*`),这样每次按下按键A,就获取A对应编码的音频,调用`play()`函数,播放他即可
// 2. 播放音频的同时方块边框有特效并且播放结束特效消失 --> 解决如何实现播放结束特效就消失 -->
// 解决办法:一播放方块边框样式就要变化,那么就事先写好一个样式,并且也给方块绑定按键编码,一按下按键就给边框添加样式
// 给边框样式变化前后添加一个过渡属性`transition`,监听这个过渡的过程,过渡一完成就移除添加的样式
// 实现
// 需求1:按下按键音频能够播放
window.addEventListener('keydown',function(event){
// 根据keyCode获取对应的音频元素和方块元素
const btn = document.querySelector(`div[data-key="${event.keyCode}"]`);
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`);
// 避免按下除A-L以外的按键抛出错误,当遇到audio为空时,直接结束函数
if (!audio) return;
// 设置每次按下按键音频都从头开始播放
audio.currentTime = 0;
// 播放音频
audio.play();
// 给方块添加样式
btn.classList.add('playing');
});
// 需求2:播放音频的同时方块边框有特效并且播放结束特效消失
// 获取所有的方块
const btns = [...document.querySelectorAll('.btn')];
btns.forEach(item => item.addEventListener('transitionend', function(event){
if (event.propertyName !== 'transform') return;
event.target.classList.remove('playing');
}))
// 实现点击方块播放音频
const audios = document.querySelectorAll('audio');
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function(){
// 设置每次按下按键音频都从头开始播放
audios[i].currentTime = 0;
// 播放音频
audios[i].play();
// 给方块添加样式
this.classList.add('playing');
})
}
</script>
</body>
</html>