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 相关文章推荐
Jquery 表单取值赋值的一些基本操作
Oct 11 Javascript
跟我学Node.js(四)---Node.js的模块载入方式与机制
Jun 04 Javascript
JQEasy-ui在IE9以下版本中二次加载的问题分析及处理方法
Jun 23 Javascript
jQuery实现列表的全选功能
Mar 18 Javascript
举例简介AngularJS的内部语言环境
Jun 17 Javascript
Node连接mysql数据库方法介绍
Feb 07 Javascript
Vue响应式添加、修改数组和对象的值
Mar 20 Javascript
微信小程序--onShareAppMessage分享参数用处(页面分享)
Apr 18 Javascript
jQuery Datatable 多个查询条件自定义提交事件(推荐)
Aug 24 jQuery
Javacript中自定义的map.js  的方法
Nov 26 Javascript
Vue监听数据渲染DOM完以后执行某个函数详解
Sep 11 Javascript
vue router 用户登陆功能的实例代码
Apr 24 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中的错误处理、异常处理机制分析
2012/05/07 PHP
初识Laravel
2014/10/30 PHP
django中的ajax组件教程详解
2018/10/18 PHP
laravel5环境隐藏index.php后缀(apache)的方法
2019/10/12 PHP
jQuery把表单元素变为json对象
2013/11/06 Javascript
javascript创建数组之联合数组的使用方法示例
2013/12/26 Javascript
node.js中RPC(远程过程调用)的实现原理介绍
2014/12/05 Javascript
javascript输出AscII码扩展集中的字符方法
2016/12/26 Javascript
vue中mint-ui环境搭建详细介绍
2017/04/06 Javascript
关于Angularjs中自定义指令一些有价值的细节和技巧小结
2018/04/22 Javascript
浅谈Vue初学之props的驼峰命名
2018/07/19 Javascript
微信小程序 MinUI组件库系列之badge徽章组件示例
2018/08/20 Javascript
JavaScript创建对象方式总结【工厂模式、构造函数模式、原型模式等】
2018/12/19 Javascript
koa大型web项目中使用路由装饰器的方法示例
2019/04/02 Javascript
图解javascript作用域链
2019/05/27 Javascript
简述ES6新增关键字let与var的区别
2019/08/23 Javascript
Vue v-for循环之@click点击事件获取元素示例
2019/11/09 Javascript
js实现点击上传图片并设为模糊背景
2020/08/02 Javascript
VUE前端从后台请求过来的数据进行转换数据结构操作
2020/11/11 Javascript
[02:55]含熏伴清风,风行者至宝、屠夫身心及典藏宝瓶二展示
2020/09/08 DOTA
Python将一个Excel拆分为多个Excel
2018/11/07 Python
python浪漫表白源码
2019/04/05 Python
Python随机函数库random的使用方法详解
2019/08/21 Python
python实现FTP文件传输的方法(服务器端和客户端)
2020/03/20 Python
django教程如何自学
2020/07/31 Python
CSS3实现苹果手机解锁的字体闪亮效果示例
2021/01/05 HTML / CSS
很酷的小工具和电子产品商城:GearBest
2016/11/19 全球购物
巴西购物网站:Estrela10
2018/12/13 全球购物
Airbnb爱彼迎官网:成为爱彼迎房东,赚取收入
2019/03/14 全球购物
Book Depository欧盟:一家领先的国际图书零售商
2019/05/21 全球购物
行政部主管岗位职责
2013/12/28 职场文书
给儿子的表扬信
2014/01/15 职场文书
过程装备与控制工程专业求职信
2014/07/02 职场文书
关于童年的读书笔记
2015/06/26 职场文书
Python数据可视化之Seaborn的安装及使用
2022/04/19 Python
安装harbor作为docker镜像仓库的问题
2022/06/14 Servers