JavaScript Drum Kit 指南(纯 JS 模拟敲鼓效果)


Posted in Javascript onJuly 23, 2017

核心代码:

<script>
 function removeTransition(event) {
  if (event.propertyName !== 'transform') return; // 过滤其中一种事件
  event.target.classList.remove('playing'); // 移除高亮的样式
 }

 function playSound(event) {
  const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`); // 根据触发按键的键码,获取对应音频
  const key = document.querySelector(`div[data-key="${event.keyCode}"]`); // 获取页面对应按钮 DIV 元素
  if (!audio) return; // 处理无效的按键事件

  key.classList.add('playing'); // 改变样式
  audio.currentTime = 0; // 每次播放之后都使音频播放进度归零
  audio.play(); // 播放相应音效
 }

 const keys = Array.from(document.querySelectorAll('.key')); // 获取页面所有按钮元素
 keys.forEach(key => key.addEventListener('transitionend', removeTransition)); // 添加 transition 事件监听
 window.addEventListener('keydown', playSound);
</script>

中文版本完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>JS Drum Kit</title>
 <link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" >
</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>
 function removeTransition(event) {
  if (event.propertyName !== 'transform') return; // 过滤其中一种事件
  event.target.classList.remove('playing'); // 移除高亮的样式
 }

 function playSound(event) {
  const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`); // 根据触发按键的键码,获取对应音频
  const key = document.querySelector(`div[data-key="${event.keyCode}"]`); // 获取页面对应按钮 DIV 元素
  if (!audio) return; // 处理无效的按键事件

  key.classList.add('playing'); // 改变样式
  audio.currentTime = 0; // 每次播放之后都使音频播放进度归零
  audio.play(); // 播放相应音效
 }

 const keys = Array.from(document.querySelectorAll('.key')); // 获取页面所有按钮元素
 keys.forEach(key => key.addEventListener('transitionend', removeTransition)); // 添加 transition 事件监听
 window.addEventListener('keydown', playSound);
</script>


</body>
</html>

英文版本完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
 <meta charset="UTF-8">
 <title>JS Drum Kit</title>
 <link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" >
</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>
  /** GOAL: When a user opens this page and presses a key that corresponds with
   * one of our div elements, we should play the audio clip associated with
   * the keypress, add a class to the specific element that matches with the keypress,
   * and then remove that class in order to reset the element to it's original state.
   */
  (()=> {
   const playSound = (e) => {
    const soundclip = document.querySelector(`audio[data-key="${e.keyCode}"]`);
    const keyelement = document.querySelector(`.key[data-key="${e.keyCode}"]`);
    if (!soundclip) return undefined; // Stop function from running if key pressed doesn't match up with our elements
    keyelement.classList.add('playing');
    // Ensures that the sound clip always plays from the beginning. Otherwise,
    // if the 'a' key is pressed twice rapidly, the soundclip will only play through
    // once.
    soundclip.currentTime = 0;
    soundclip.play(); // Play sound
   }
   const removeTransition = (e) => {
    // skip if it's not a transform event
    if (e.propertyName !== 'transform') return undefined;
    e.target.classList.remove('playing');
   }
   // Find all elements in the document with a class 'key'
   const keys = document.querySelectorAll('.key');
   // Listen for any `keydown` events that occur on this browser window instance (this page)
   // When a `keydown` event is observered, trigger the `playSound` function, passing in the
   // `keydown` event as the argument (e)
   window.addEventListener('keydown', playSound);
   keys.forEach(key =>
    key.addEventListener(
     'transitionend',
     (e) => removeTransition.call(key, e)
    ));
  })();
 </script>

</body>

</html>

在线演示地址:http://demo.3water.com/js/2017/JavaScript30/JavaScriptDrumKit/index-FINISHED.html

请在chrome浏览器下查看效果。

Javascript 相关文章推荐
JavaScript 对象模型 执行模型
Dec 06 Javascript
Jquery多选下拉列表插件jquery multiselect功能介绍及使用
May 24 Javascript
浅谈EasyUI中Treegrid节点的删除
Mar 01 Javascript
深入理解JavaScript系列(37):设计模式之享元模式详解
Mar 04 Javascript
关于Vue.js 2.0的Vuex 2.0 你需要更新的知识库
Nov 30 Javascript
vue.js实现价格格式化的方法
May 23 Javascript
jQuery plugin animsition使用小结
Sep 14 jQuery
JavaScript分步实现一个出生日期的正则表达式
Mar 22 Javascript
JS实现数组去重及数组内对象去重功能示例
Feb 02 Javascript
layui之数据表格--与后台交互获取数据的方法
Sep 29 Javascript
对vue生命周期的深入理解
Dec 03 Vue.js
聊聊JS ES6中的解构
Apr 29 Javascript
JavaScript30 一个月纯 JS 挑战中文指南(英文全集)
Jul 23 #Javascript
jquery实现下拉菜单的手风琴效果
Jul 23 #jQuery
基于Vue.js实现tab滑块效果
Jul 23 #Javascript
JavaScript判断浏览器和hack滚动条的写法
Jul 23 #Javascript
原生js FileReader对象实现图片上传本地预览效果
Mar 27 #Javascript
JavaScript解析任意形式的json树型结构展示
Jul 23 #Javascript
Node.js如何实现注册邮箱激活功能 (常见)
Jul 23 #Javascript
You might like
PHP随手笔记整理之PHP脚本和JAVA连接mysql数据库
2015/11/25 PHP
YII Framework框架教程之缓存用法详解
2016/03/14 PHP
php实现图片缩略图的方法
2016/03/29 PHP
nginx 设置多个站跨域
2021/03/09 Servers
iis6+javascript Add an Extension File
2007/06/13 Javascript
JS 实现图片直接下载示例代码
2013/07/22 Javascript
js获取页面传来参数的方法
2014/09/06 Javascript
从零学习node.js之搭建http服务器(二)
2017/02/21 Javascript
原生javascript上传图片带进度条【实例分享】
2017/04/06 Javascript
获取url中用&amp;隔开的参数实例(分享)
2017/05/28 Javascript
基于javaScript的this指向总结
2017/07/22 Javascript
Vue.js实现按钮的动态绑定效果及实现代码
2017/08/21 Javascript
jquery自定义显示消息数量
2017/12/19 jQuery
vue自定义底部导航栏Tabbar的实现代码
2018/09/03 Javascript
微信小程序自定义组件的实现方法及自定义组件与页面间的数据传递问题
2018/10/09 Javascript
Nuxt默认模板、默认布局和自定义错误页面的实现
2020/05/11 Javascript
[03:40]DOTA2亚洲邀请赛小组赛第二日 赛事回顾
2015/01/31 DOTA
[54:10]完美世界DOTA2联赛PWL S2 Magma vs FTD 第二场 11.29
2020/12/03 DOTA
python通过opencv实现批量剪切图片
2017/11/13 Python
Python编程图形库之Pillow使用方法讲解
2018/12/28 Python
Python装饰器用法实例分析
2019/01/14 Python
Python3.5基础之NumPy模块的使用图文与实例详解
2019/04/24 Python
python argparse模块通过后台传递参数实例
2020/04/20 Python
解决Keras 中加入lambda层无法正常载入模型问题
2020/06/16 Python
python绘制汉诺塔
2021/03/01 Python
CSS3 3D旋转rotate效果实例介绍
2016/05/03 HTML / CSS
JavaScript+Canvas实现自定义画板的示例代码
2019/05/13 HTML / CSS
西北政法大学自主招生自荐信
2014/01/29 职场文书
企业授权委托书范本
2014/04/02 职场文书
电子商务专业自荐信
2014/06/02 职场文书
店铺转让协议书
2014/12/02 职场文书
小学少先队辅导员述职报告
2015/01/10 职场文书
公司表扬稿范文
2015/05/05 职场文书
2015年酒店销售部工作总结
2015/07/24 职场文书
小学思想品德教学反思
2016/02/24 职场文书
Python matplotlib绘制雷达图
2022/04/13 Python