# [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"] ```