---
# System prepended metadata

title: Day1 - Drum Kit
tags: [JS30, keyboardEvent]

---

# [Day1] - Drum Kit(JS30 x 鐵人30 x MDN)

## 今天我們來做一個可以演湊鼓聲的網頁

*  新增事件監聽：[EventTarget: addEventListener() method](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
*  節點選取：[Document: querySelector()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)、[Document: querySelectorAll()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)
*  元素Class修改：[Element: classList property](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList)
*  影音播放：[HTMLMediaElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement)



![](https://cdn.discordapp.com/attachments/1104455124975362148/1141639582698451055/e16d279c96f67a76.gif)

觀察index-Start.html可以發現作者已經創好各個按鍵容器及存放音檔的Html Element，都擁有屬性"data-key"且兩兩成對，上網搜尋「鍵盤鍵碼值對照表」即可發現鍵盤的按鍵K即對應到鍵碼值75
```html    
    <div data-key="65" class="key">
      <kbd>A</kbd>
      <span class="sound">clap</span>
    </div>
```
```html
<audio data-key="65" src="sounds/clap.wav"></audio>
```
根據題目需求我們現在要的事就是當按下按鍵時，要透過Javascriptd去控制讓對應相同data-key值的```<audio>```tag進行播放


1. 使用[EventTarget: addEventListener() method](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)為這個視窗(Window)新增一個針對[keydown event按鍵按下](https://developer.mozilla.org/en-US/docs/Web/API/Document#keydown)的事件監聽器，當有按鍵按下都會執行函式playSound
```javascript
window.addEventListener("keydown", playSound);
```
2. playSound 是一個專門為event hanlder寫的function，e代表事件發生時會自動傳入的物件，裡面記載著這個事件發生當下的各種詳細資訊(如下圖)
![](https://hackmd.io/_uploads/rkRHpHc2n.png)

函式 playSound中
(1)(2)使用.keycode去[Document: querySelector() method](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)取得對應的```<audio>```及```<div data-key="65" class="key">```。
(3)若沒有找到對應的按鈕及音檔節點則```return```不做任何事情，若有找到才做後續的步驟。
(4)將對應```<audio>```的[HTMLMediaElement: currentTime property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime)先初始化為零。
(5)再使用[HTMLMediaElement:play() method](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play)進行播放。
(6)最後將代表該按鍵的容器使用[Element: classList property的add()method](https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/add)為其掛上"playing"這個動畫CSS class。

```javascript
function playSound(e) {
  const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);//(1)
  const button = document.querySelector(`.key[data-key="${e.keyCode}"]`);//(2)
  if (!audio || !button) return;//(3)
  audio.currentTime = 0;//(4)
  audio.play();//(5)
  button.classList.add("playing");//(6)
```

3. 最後我們要針對移除"playing"這個動畫CSS class再寫一組事件監聽器

(1)這次我們改用[Document: querySelectorAll() method](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)先取得擁有"key"這個className的所有節點回傳為一個([NodeList陣列](https://developer.mozilla.org/en-US/docs/Web/API/NodeList))並把它存放於keyList變數中
(2)以keyList使用[NodeList: forEach() method](https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach)將每個符合的節點都新增一個針對[transitionEnd EventCSS轉變結束](https://developer.mozilla.org/en-US/docs/Web/API/Document#keydown)的事件監聽器，當CSS轉變結束時會執行函式removeTransition
函式 removeTransition中
(3)我們先判定事件的[TransitionEvent: propertyName property](https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent/propertyName)若不是"transform"則```return```不做任何事情
(4)若有找到就從自己的classList中使用[Element: classList remove()method](https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/remove)把"playing"這個class移除
```javascript
const keyList = document.querySelectorAll(".key"); // (1)
keyList.forEach((key) =>key.addEventListener("transitionend", removeTransition));//(2)

function removeTransition(e) {
  if (e.propertyName !== "transform") return; //(3)
  this.classList.remove("playing"); //(4)
}
```
### [👉Github Demo頁面👈](https://yang840817.github.io/Javascript-30/01%20-%20JavaScript%20Drum%20Kit/)

### [👉好想工作室15th鐵人賽看板👈](https://yang840817.github.io/GoodIdeasStudio-2023ironman/)

#### 參考資料
1. Javascript 30 官網
https://javascript30.com/
2. MDN官網
https://developer.mozilla.org/en-US/

```JSON
"tag": ["15th鐵人賽","Javascript 30"]
```