实现的效果如下:
当按下键盘上对应字母时,产生不同的击鼓声音,相应盒子的样式发生改变。
这个效果是JavaScript30天挑战的第一个小项目,具体项目可见如下官网:
JavaScript30 挑战官网地址: javascript30.com/
JavaScript30 挑战github源码地址: github.com/wesbos/Java…
在我做的时候,我将它分成了css和js两个部分:
css方面,我们需要一个大盒子装9个小盒子,为使他们整齐的排列在页面中间,我们需要用到flex布局,添加justify-content
和align-items
实现该效果,然后在小盒子中添加span等元素来写入文字。
如何实现对应的鼓声音效呢? 我们需要用到audio
标签,然后为每个audio
和小盒子中放对应字母的盒子添加相同的data-属性,方便之后在js中选出对应的元素。不了解data-属性的可以看这个博客:
(1条消息) html5中data-*属性的作用是什么_persistence勿忘初心-CSDN博客
接着我们来看js的部分。首先我们来分析一下我们需要做出的效果:
(1)点击键盘上对应字母时,会发出相应的击鼓声;
(2)点击键盘上对应字母时,装字母的盒子外边框会出现高亮,其中的字母会放大;
(3)高亮和字母放大效果产生之后,效果会消失,恢复原状
下面我们对应这三点展开解释:
首先我们需要用到onkeydown
响应函数,传入event参数,表示当键盘上有键按下时,会进入该函数;我们如何知道按下的是哪个键呢?这时候需要用到event参数的keyCode属性,该属性和键盘上的键一一对应,我们可以通过console.log(event.keyCode)
获取;
接着,知识点来了,我们要如何选择对应的键呢?这时我们之前提到的data-属性就派上用场了,拿audio举例,我们需要通过document.querySelector(audio[data-key="${event.keyCode}"])
来获取对应的元素。
current Time
设置为0,然后调用play()
函数令该音效播放;classList
属性中的add()
函数,为该盒子添加样式。ontransitionend
响应函数或者使用addEventListener
监听transitionend事件,当前面的效果产生之后,会进入该事件响应函数,我们可以在其中实现:当事件的transition未进行时return,当已进行时抵用class List
属性中的remove()
函数删掉之前添加的css选择器。具体可以见下面的代码一些小tips:
在transitionend事件的响应函数中,我们需要判断事件的propertyName属性是否为transform,这一点我们可以通过console.log
查看该事件,在其中就能查看到该属性;以及之后的target,都可以查看到。
代码如下:
<!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>Document</title> <style> html{ background: url(background.jpg) bottom center; background-size: cover; } *{ margin: 0; padding: 0; } .container { display: flex; justify-content: center; align-items: center; height: 100vh; /* 整个大盒子的内容放中间 */ } .box { width: 90px; border: 4px solid black; background-color: rgba(0, 0, 0, .4); text-align: center; margin:10px; padding:10px; transition: all .07s ease; /* 要加动画 */ } kbd { font-size: 34px; color: white; display: block; text-shadow: 0 0 2px black; } .clap { font-size: 14px; margin-top: 5px; color: #ffc600; display: block; text-transform: uppercase; letter-spacing: 2px; /* 字母都变成大写 */ } .high { border-color: #ffc600; box-shadow: 0 0 1rem #ffc600; transform: scale(1.1); } </style> </head> <body> <div class="container"> <div class="box" data-key="65"> <kbd>A</kbd> <span class="clap">boom</span> </div> <div class="box" data-key="83"> <kbd>S</kbd> <span class="clap">clap</span> </div> <div class="box" data-key="68"> <kbd>D</kbd> <span class="clap">hihat</span> </div> <div class="box" data-key="70"> <kbd>F</kbd> <span class="clap">kick</span> </div> <div class="box" data-key="71"> <kbd>G</kbd> <span class="clap">openhat</span> </div> <div class="box" data-key="72"> <kbd>H</kbd> <span class="clap">ride</span> </div> <div class="box" data-key="74"> <kbd>J</kbd> <span class="clap">snare</span> </div> <div class="box" data-key="75"> <kbd>K</kbd> <span class="clap">tink</span> </div> <div class="box" data-key="76"> <kbd>L</kbd> <span class="clap">tom</span> </div> </div> <audio src="sounds/boom.wav" data-key="65"></audio> <audio src="sounds/clap.wav" data-key="83"></audio> <audio src="sounds/hihat.wav" data-key="68"></audio> <audio src="sounds/kick.wav" data-key="70"></audio> <audio src="sounds/openhat.wav" data-key="71"></audio> <audio src="sounds/ride.wav" data-key="72"></audio> <audio src="sounds/snare.wav" data-key="74"></audio> <audio src="sounds/tink.wav" data-key="75"></audio> <audio src="sounds/tom.wav" data-key="76"></audio> <script> function fun(e){//e是一个transitionevent事件 console.log(e) if(e.propertyName !== 'transform') return; e.target.classList.remove('high'); } let box=Array.from(document.querySelectorAll(".box")); box.forEach(x=>x.addEventListener("transitionend",fun)); window.onkeydown = function (event) { let now = document.querySelector(`div[data-key="${event.keyCode}"]`); let sound=document.querySelector(`audio[data-key="${event.keyCode}"]`); if(!now || !sound) return; now.classList.add("high"); sound.currentTime=0; sound.play(); } </script> </body> </html>