JavaScript1/30: Drum Kit

JavaScript30 为Wes Bos推出的一项为期30天的挑战,旨在帮助人们用纯JavaScript来实现效果,初学者若想在JS方面快速精进,不妨一试。如今你看到的是该系列总结的第一篇,不知什么时候能作完30题,就不在此信誓旦旦立flag了。javascript

个人项目地址是 js 1/30css

实现效果

利用JS实现模拟打鼓的效果,敲击键盘字母(A-L),便可播放对应声音,同时当前字母伴随敲击声效出现动画。 html

查看 demojava

解题思路

  • 监听键盘事件
window.addEventListener('keydown', playaudio);
复制代码
  • 建立function playaudio()
    • 利用当前e.keyCode来获取对应键码的div标签和audio标签。
    • 判断对应的audio是否存在,如果则播放该音频,并添加按钮样式。
  • 添加transitionend事件,移除样式,恢复原状。

初始代码

页面基础布局

<div class="keys">
    <div data-key="65" class="key">
      <kbd>A</kbd>
      <span class="sound">clap</span>
    </div>
    ······
    <!-- B-K部分代码省略,请参阅代码 -->
    <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="76" src="sounds/tink.wav"></audio>
复制代码

CSS代码

html {
  font-size: 10px;
  background: url(http://i.imgur.com/b9r5sEL.jpg) bottom center;
  background-size: cover;
  /* 把背景图像扩展至足够大,以使背景图像彻底覆盖背景区域。 */
}
body,html {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}

.keys {
  display: flex;
  flex: 1;
  min-height: 100vh;
  /* 设置段落的最小高度,其中vh是可视区百分比高度单位,如1vh等于可视区高度的百分之一 */
  align-items: center;
  /* 弹性盒子元素在该行的侧轴(纵轴)上居中放置。 */
  justify-content: center;
  /* 弹性盒子元素将向行中间位置对齐。该行的子元素将相互对齐并在行中居中对齐, 同时第一个元素与行的主起始位置的边距等同与最后一个元素与行的主结束位置的边距 */
}

.key {
  border: .4rem solid black;
  border-radius: .5rem;
  /* 向 div 元素添加圆角边框 */
  margin: 1rem;
  font-size: 1.5rem;
  padding: 1rem .5rem;
  transition: all .07s linear;
  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;
}
复制代码

解题难点

1.如何将键盘A-L按键与对应标签及音频联系起来?

在初始代码中,咱们能够看到div.key和audio都传入了一个data-key,能够此为突破口,只需找到与e.keyCode等值的标签便可。git

const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`div[data-key="${e.keyCode}"]`);
复制代码

经过此网站可快速查询keyCode.github

2.当持续按住按键,如何使得音频立刻相应?

设置audio播放时间为0函数

audio.currentTime = 0;
复制代码

3.样式生效后,如何使得页面标签恢复原状?

添加transitionend事件,移除样式。 transitionend 事件会在 CSS transition 结束后触发。布局

4.长时间按住某个按键以后,会发现一个bug,div.key动画挥之不去。

一样添加键盘监听事件,利用keyup移除效果。flex

window.addEventListener('keyup',removeT);
复制代码

JavaScript完整代码以下:

<script>
    function removeT(e) {
      if (e.propertyName !== 'transform') return;
      e.target.classList.remove('playing');
    }

    function playaudio(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();
    }

    const keys = document.querySelectorAll('.key');
    keys.forEach(key => key.addEventListener('transitionend', removeT));
    window.addEventListener('keydown', playaudio);
    window.addEventListener('keyup', removeT);
复制代码

注意事项

  • 区分大小写: propertyName,keyCode等等,这道题我作了两遍,两次都摔在了这个坑里,引觉得戒。
  • querySelectorAll: 返回与指定的选择器组匹配的文档中的元素列表 ,须要注意的是返回对象为 NodeList ,而不是Array,也能够用Array.from()将其转换为数列,固然即便不转换,也可使用forEach函数遍历。
  • forEach函数:较for循环更为简洁,示例以下:
var arr = [1, 2, 3];
for(var i = 0; i < arr.length; i++) {  
    console.log(arr[i]);
}
复制代码

等同于,动画

var arr = [1, 2, 3];
arr.forEach((val) => {  
    console.log(arr[i]);
})
复制代码

也可用用reduce、map、filter这样的函式代替,详见该网站

反引号``包裹字符串,常与${变量}连用。 普通字符串:

var a = 5;
var b = 10;
console.log("Fifteen is " + (a + b) + " and\nnot " + (2 * a + b) + ".");
// "Fifteen is 15 and
// not 20."
复制代码

模板字符串:

var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and\nnot ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."
复制代码

另,在回顾总结中,发现liyuechun的博客,受益良多,记录一笔。

相关文章
相关标签/搜索