20分钟用原生JavaScript实现键盘打击乐

01 – JavaScript Drum Kit

JavaScript 30 是由 WES BOS 制作的纯 JavaScript 教学,在该教程中一共会实现30个案例。本文用于记录在 DEMO 制作过程中遇到的问题以及思考。本文首发于个人博客,Enjoy Reading!

需求

键盘按下后,播放出对应按键的声音,并且在页面上的按钮显示一个简单的特效。

在线 DEMO
源码

步骤

Step1: 监听键盘事件

为了让网页在全局下监听键盘,使用 window.addEventListener('keydown', function(){})

补充:keydown和keypress的区别

  • keydown 会被所有按键触发,但是 keypress 只会被能生成字符值的按键触发。例如:方向键能触发keydown,但是不能触发keypress
  • keydown 的 event keycode 来说明是哪个按键触发了事件,而 keypress 提供的 keycode 只会说明触发事件是哪个字符。例如:当键盘按下 akeyboard 会报告 65,而 keypress 会报告 97。值得注意的是,A 在任何的事件中都会报告为65

Step2: 创建播放函数

  1. 利用 keyCodedata-key[] 判断按键对应的音频以及div元素。
  2. 使对应的div元素添加上 playing 的样式。
  3. audio 的播放时间设为0,确保每次播放前音频从头开始。
  4. 播放音频。

补充1:audio其他常用的属性及方法

  1. 属性
    • autoplay:布尔值属性;声明该属性,音频会尽快自动播放,不会等待整个音频文件下载完成。
    • controls:如果声明了该属性,浏览器将提供一个包含声音,播放进度,播放暂停的控制面板,让用户可以控制音频的播放。
    • loop:布尔属性;如果声明该属性,将循环播放音频。
  2. 方法
    • pause:暂停播放。

补充2:classList

  • 相比于之前用 js 操控 CSS,例如:

    document.style.background="red";

    document.style.fontSize="24";

    相当于【元素的样式被改变了两次】,可能会导致回流和重绘,降低JavaScript性能。

  • 必要的时候可以使用 list 列表的形式,例如:

    document.getElementById("myDIV").classList.add("mystyle");

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();
  }
复制代码
.playing {
  transform: scale(1.1);
  border-color: #ffc600;
  box-shadow: 0 0 1rem #ffc600;
}
复制代码

Step3: 监听transitione结束事件

  1. 获取所有包含 className=key 的元素。
  2. 当该元件触发特效并结束时触发函数。
const key = Array.from(document.querySelectorAll('.key'));
key.forEach(key => key.addEventListener('transitionend', function(){}))
复制代码

补充:ArrayForm

  • document.querySelectorAll() 获取到的元素是NodeList,虽然 NodeList 不是 Array ,但仍然可以使用 forEach 进行迭代,不过老旧的浏览器较为过时,没有实现 NodeList.forEach() 。可以使用 Array.prototype.forEach()Array.form() 来规避这一问题。

Step4: 创建removeTransition函数

  1. 判断传入事件的 peopertyName 是否为 transform,若否则退出。
  2. 若为 transform,则移除 playing 样式。
function removeTransition(e) {
  if(e.propertyName !== 'transform') return;
  e.target.classList.remove('playing');
}
复制代码

思考

在原案例中使用了CSS的排版语法:

.keys {
    display: flex; /* 使用flex要现在元素内声明flex */
    flex: 1; /* 简写,全称为flex: flex-grow|flex-shrink|flex-basis*/
    min-height: 100vh; /* vh代表view height, 百分比呈现 */
    align-items: center; /* 声明为flex后才有效的属性,垂直居中 */
    justify-content: center;/* 声明为flex后才有效的属性,水平居中 */
}
复制代码

参阅

Document: keydown event – WebAPIs | MDN

<audio> – HTML | MDN

NodeList – Web APIs | MDN

Element.classList – Web APIs | MDN

flex – CSS: Cascading Style Sheets | MDN

JS30紀錄&心得 | Gua’s Note

JavaScript30 | a90100

在文章的最后,感谢 WES BOS 等国内外大佬将优秀作品开源,让学习的门槛变得更低,enjoy Coding!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享