创建页面及样式
创建index.html
涉及到的知识点:
data-
data-* 全局属性 构成一类称为自定义数据属性的属性,允许通过脚本在HTML 和其 DOM 表示之间交换专有信息。所有这些自定义数据都可以通过属性设置的元素的 HTMLElement 接口来访问。
HTMLElement.dataset 属性可以访问它们。 * 可以使用遵循 xml名称生产规则 的任何名称来被替换,并具有以下限制:
该名称不能以xml开头,无论这些字母用于什么情况; 该名称不能包含任何分号 (U+003A); 该名称不能包含A至Z的大写字母。 注意,HTMLElement.dataset 属性是一个StringMap,并且自定义数据属性 data-test-value 可以通过 HTMLElement.dataset.testValue ( 或者是 HTMLElement.dataset[“testValue”] ) 来访问,任何破折号(U+002D) 都会被下个字母的大写替代(驼峰拼写)。
参考 MDN: data-*
<kbd>
HTML键盘输入元素() 用于表示用户输入,它将产生一个行内元素,以浏览器的默认monospace字体显示。
<kbd>cmd</kbd>
参考 MDN: kbd
创建index.css
涉及到的知识点:
CSS 长度值
单位 | 含义 |
---|---|
em | 相对于父元素的字体大小 |
ex | 相对于小写字母”x”的高度 |
rem | 相对于根元素字体大小 |
vw | 相对于视窗的宽度:视窗宽度是100vw |
vh | 相对于视窗的高度:视窗高度是100vh |
vm | 相对于视窗的宽度或高度,取决于哪个更小 |
% | 相对于父元素。正常情况下是通过属性定义自身或其他元素 |
vw
和 vh
称为视口单位,允许我们更杰基恩浏览器窗口定义的大小
在桌面端,视口指的是在桌面端,指的是浏览器的可视区域;而在移动端,它涉及3个视口:Layout Viewport(布局视口),Visual Viewport(视觉视口),Ideal Viewport(理想视口)。
视口单位中的“视口”,桌面端指的是浏览器的可视区域;移动端指的就是Viewport中的Layout Viewport。
添加 JS 代码
监听按键 & 添加动画 & 音效播放
- 监听页面的
keydown
事件,触发playAudio
函数
window.addEventListener('keydown', playSound);
给
key
添加动画怎么监听我们按了哪个按键呢?每一个按键都有自己的KeyCode,我们通过按键的KeyCode来判断
在这里我们用到了ES6的模板字符串,${e.keyCode},可以动态的将按键的Keycode传过去,以使audio动态的获取每一个按键绑定的 audio。需要注意的是模板字符串一定要使用”`“(Esc下面那个键)包裹,而不是双引号。
给
key
添加playing
类,展示小动画
const key = document.querySelector(`div[data-key="${e.keyCode}"]`);
if(!key) return;
key.classList.add('playing');
给
audio
添加播放我们注意到
audio.play()
;前面一行是audio.currentTime = 0
;,这是因为,如果没有在播放音效前将该音乐重置,会发生以下情况,当我连续点击某一按键的时候,只有第一次点击会响,第二次第三次连续的点击可能没声音。所以在每一次点击之前重置音效是很有必要的。play()
方法开始播放当前的音频或视频。
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
if (!audio) return;
audio.currentTime = 0;
audio.play();
动画结束后移除动画
- 监听每一个按键元素的t
transitionend
事件,当按键元素的动画结束后会触发stopTransition
函数。
transitionend 事件会在 CSS transition 结束后触发. 当transition完成前移除transition时,比如移除css的transition-property 属性,事件将不会被触发.如在transition完成前设置 display 为”none”,事件同样不会被触发。
- 首先在
removeTransition
函数中可以输出事件e
的内容,会输出该动画每一步具体的变化,发现其中会有propertyName
属性,可以通过判断propertyName
等于其中的一个值(例如’transform’),等于该值就移除playing
类,也即移除动画。
propertyName
: The name of the CSS property associated with the transition.
- 在定位元素的时候,可以使用this也可以使用
e.target
,可以简单这么理解,this
值的是谁出发了这次事件,也就是key
,就等同于事件的目标(e.target
)。
function removeTransition(e) {
if (e.propertyName !== 'transform') return;
e.target.classList.remove('playing');
}
- 解除绑定
选取 class 为
key
的每个元素,然后使用Array.from
方法创建一个新数组,再使用forEach
方法遍历该数组,添加监听事件,一旦动画结束,就执行移除动画事件
Array.from
: 从一个类似数组或可迭代对象中创建一个新的数组实例
forEach
:对数组的每个元素执行一次提供的函数
const keys = Array.from(document.querySelectorAll('.key'));
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
完整代码戳我的 lttxzmj GitHub,欢迎 star。