简介 项目效果 :点击查看
用JS制作一个爵士鼓的页面,通过敲击键盘上不同的字母,会发出不同的声音,并且页面上会伴随着敲击的动画。
想要实现以上效果,大致思路和解决方案如下:
检测到键盘上什么键被按下–监听keydown
事件
在按键被按下的时候,播放音效–audio.play()
在按键被按下的同时,播放动画–Element.classList.add('className')
在动画结束后,移除动画,不然之后再点击不会有任何效果–Element.classList.remove('className')
基础语法 一些 ES6 语法
const
:声明一个只读的常量,标识符的值只能赋值一次。
`字符串 ${ 变量、属性名 } `:模板字面量(Template literals)中用于表示模板字符串的标识。特点是字符串首尾用反引号(`),内部的模板部分用 ${ } 括起来表示,具体请看MDN文档 。简单例子如下:
1 2 3 4 5 6 var a = 1 ;var b = 2 ;console .log ("三是" + (a + b) + "不是" + (2 * a + b)); console .log (`三是${a + b} 不是${2 * a + b} ` );
forEach
与箭头函数使用 document.querySelector
获取一组符合 CSS 选择符的元素快照,类型为 NodeList(此对象是对于文档的实时运行的动态查询),对其进行遍历时可采用 forEach
方法。
1 2 3 4 5 6 7 8 9 10 11 nums.forEach (v => { if (v % 5 === 0 ) fives.push (v); }) nums.forEach (function (v ) { if (v % 5 === 0 ) five.push (v); })
页面基础布局 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > JS Drum Kit</title > <link rel ="stylesheet" href ="style.css" > </head > <body > <div class ="keys" > <div data-key ="65" class ="key" > <kbd > A</kbd > <span class ="sound" > clap</span > </div > <div data-key ="83" class ="key" > <kbd > S</kbd > <span class ="sound" > hihat</span > </div > <div data-key ="68" class ="key" > <kbd > D</kbd > <span class ="sound" > kick</span > </div > <div data-key ="70" class ="key" > <kbd > F</kbd > <span class ="sound" > openhat</span > </div > <div data-key ="71" class ="key" > <kbd > G</kbd > <span class ="sound" > boom</span > </div > <div data-key ="72" class ="key" > <kbd > H</kbd > <span class ="sound" > ride</span > </div > <div data-key ="74" class ="key" > <kbd > J</kbd > <span class ="sound" > snare</span > </div > <div data-key ="75" class ="key" > <kbd > K</kbd > <span class ="sound" > tom</span > </div > <div data-key ="76" class ="key" > <kbd > L</kbd > <span class ="sound" > 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 > </script > </body > </html >
说到技术概念上的特殊样式时,就要提到 标签。正如你已经猜到的,它用来表示文本是从键盘上键入的。 浏览器通常用等宽字体来显示该标签中包含的文本。 标签经常用在于计算机相关的文档和手册中。例如:
1 键入 <kbd>quit</kbd> 来退出程序,或者键入 <kbd>menu</kbd> 来返回主菜单。
页面里通过data-key将页面展示的内容和audio关联起来。使用方法如下介绍:
1 2 3 4 5 <ul > <li data-animal-type ="bird" > Owl</li > <li data-animal-type ="fish" > Salmon</li > <li data-animal-type ="spider" > Tarantula</li > </ul >
① data-* 属性用于存储页面或应用程序的私有自定义数据。 ② data-* 属性赋予我们在所有 HTML 元素上嵌入自定义 data 属性的能力。 ③ 属性名不应该包含任何大写字母,并且在前缀 “data-“ 之后必须有至少一个字符 ④ 属性值可以是任意字符串
语法:
1 <element data-*="somevalue">
属性值:
值
描述
somevalue
规定属性的值(以字符串)。
主要CSS代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 html { font-size : 10px ; background : url ('./3.jpg' ) bottom center; background-size : cover; } body ,html { margin : 0 ; padding : 0 ; font-family : sans-serif; } .keys { display : flex; flex : 1 ; min-height : 100vh ; align-items : center; justify-content : center; } .key { border : .4rem solid black; border-radius : .5rem ; margin : 1rem ; font-size : 1.5rem ; padding : 1rem .5rem ; transition : all .07s ease; width : 10rem ; text-align : center; color : white; background : rgba (0 , 0 , 0 , 0.4 ); text-shadow : 0 0 .5rem black; } .playing { transform : scale (1.1 ); border-color : #ffc600 ; box-shadow : 0 0 1rem #ffc600 ; } kbd { display : block; font-size : 4rem ; } .sound { font-size : 1.2rem ; text-transform : uppercase; letter-spacing : .1rem ; color : #ffc600 ; }
主要属性有以下几个:
html
中有一个样式为font-size: 10px;
,在本案例中,1rem
就是10px,rem是以html中的font-size
为参照物,1.2rem
就是12px
。
transform: scale(1.1);
–该属性在键盘被点击时将该元素缩放至原来的1.1倍。
.key{border: .4rem solid black;} .playing{border-color: #ffc600;}
–这两条属性在按键点击的时候改变边框颜色。
.key{text-shadow: 0 0 .5rem black;} .playing{box-shadow: 0 0 1rem #ffc600;}
–这两条属性在按键点击的时候改变阴影的效果
transition: all .07s ease;
–定义以上动画在0.07秒内完成。 我们注意到我们定义了.palying
类,在按键按下的时侯为该元素添加playing
类,在结束后移除playing
类。
JS代码 按键监听&音效播放&添加动画 1 2 3 4 5 6 7 8 9 10 11 12 13 function playSound (e ) { const audio = document .querySelector (`audio[data-key="${e.keyCode} "]` ); const key = document .querySelector (`div[data-key="${e.keyCode} "]` ); if (!audio) return ; key.classList .add ('playing' ); audio.currentTime = 0 ; audio.play (); } window .addEventListener ('keydown' , playSound);
监听页面的keydown事件,触发playAudio函数。
通过KeyCode检测我们按下的键盘按钮是哪个按钮。
A -> 65
B -> 66
C -> 67
D -> 68
E -> 69
F -> 70
G -> 71
H -> 72
I -> 73
J -> 74
K -> 75
L -> 76
M -> 77
N -> 78
O -> 79
P -> 80
Q -> 81
R -> 82
S -> 83
T -> 84
U -> 85
V -> 86
W -> 87
X -> 88
Y -> 89
Z -> 90
在这里我们用到了ES6的模板字符串,${e.keyCode}
,可以动态的将按键的Keycode
传过去,以使audio
动态的获取每一个按键绑定的audio
。需要注意的是模板字符串一定要使用”`”(Esc下面那个键)包裹,而不是双引号。
我们注意到audio.play();
前面一行是audio.currentTime = 0;
,这是因为,如果没有在播放音效前将该音乐重置,会发生以下情况,当我连续点击某一按键的时候,只有第一次点击会响,第二次第三次连续的点击可能没声音。所以在每一次点击之前重置音效是很有必要的。
key.classList.add('playing');
可以在按键点击的同时为该元素添加playing类,展示小动画。
if(!audio) return; if(!key) return;
因为并不是每一个按键都有音效,当用户点击了非绑定音效按键,及时退出函数是很好的习惯。
动画结束后移除动画 1 2 3 4 5 6 7 function removeTransition (e ) { if (e.propertyName !== 'transform' ) return ; e.target .classList .remove ('playing' ); } const keys = Array .from (document .querySelectorAll ('.key' ));keys.forEach (key => key.addEventListener ('transitionend' ,stopTransition));
监听每一个按键元素的transitionend
事件,当按键元素的动画结束后会触发removeTransition
函数。
首先在removeTransition
函数中可以输出事件e的内容,会输出该动画每一步具体的变化,发现其中会有propertyName
属性,可以通过判断propertyName
等于其中的一个值(例如’transform’),等于该值就移除playing
类,也即移除动画。
在定位元素的时候,可以使用this
也可以使用e.target
,可以简单这么理解,this
值的是谁出发了这次事件,也就是key
,就等同于事件的目标(e.target).
解决难点 如何将键盘按键与页面按钮对应起来? 连接的帮手是 keydown
事件中的 keyCode
属性,keyCode
属性的值和 ASCII 编码值相同(对应小写字母)。在这个网站 可以用按键盘来查看对应的键码。
我们能获取到的初始页面中,按钮 div
和音频 audio
标签中都添加了一个属性 data-key
用于存储对应的键码,这样做的目的是,添加键盘事件监听后,触发键盘事件时即可获取事件的 keyCode
属性值,以此为线索,操作对应的按钮及音频。
1 2 const audio = document .querySelector (`audio[data-key="${e.keyCode} "]` );const key = document .querySelector (`div[data-key="${e.keyCode} "]` );
如何保证按键被按住不放时,可以马上响起连续鼓点声? 每次播放音频之前,设置播放时间戳为 0:
1 2 3 var audio = document .getElementById ("video" ); audio.currentTime = 0 ; audio.play ();
如何使页面按钮恢复原状? 利用一个叫 transitionened
的事件,它在 CSS transition 结束后会被触发。我们就可以利用这个事件,在每次打鼓的效果(尺寸变大、颜色变化)完成之后,去除相应样式。
在这个页面中,发生 transition
的样式属性不止一个(box-shadow
, transform
, border-color
),所以需要添加一个判断语句,使每发生一次按键事件时,只去除一次样式。
1 2 3 4 5 funciton remove(event) { if (event.propertyName !== 'border-left-color') return; this.classList.remove('playing'); // event.target.classList.remove('playing'); }