跟著做 JS 30 第一個作品 Drum kit
主要是用這個頁面呈現,搭配鍵盤上面的按鈕做出可以有聲音互動的頁面
跟著做出來的範例

想法示意圖
一開始從 KB 取得 keycode,接下來就可以連結到兩個部分:
- 音效 music: 按下去時候的鼓聲
- DOM style: 按下去時候的變大特效
然後從特效這邊會延伸出去一些東西:
- add class: 放大的黃圈特效
- transform: add class 之後他會做這個動畫變形
- transition: 這個跟 transform 是連動的
- remove class: 移除後恢復按下去之前的樣子

完整程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <script> ;(function () { function playHandler(e) { const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`); if (audio) { audio.currentTime = 0; audio.play(); } const dom = document.querySelector(`div[data-key="${e.keyCode}"]`); if (dom) dom.classList.add('playing'); }
function transitionendHandler(e) { console.log(e);
if (e.propertyName === 'transform') { e.currentTarget.classList.remove('playing') } } window.addEventListener('keydown', playHandler) document.querySelectorAll('.key').forEach(function (key) { key.addEventListener('transitionend', transitionendHandler) }) })() </script>
|
keyboardEvent 裡面的值
印出來之後裡面會有很多 property,然後裡面有兩個比較重要的會是 key 跟 keycode

1 2 3 4 5 6
| window.addEventListener('keydown', playHandler);
function playHandler(e){ console.log(e)
|
下圖可以看到那些 keycode 可以放在 HTML 裡面待會讓 JS 去做對應


Play music
這邊使用了 ES6 的 template string (``)
所以她後面才會加${}並且裡面放的就是 keycode 讓他抓取到鍵盤按下去的物件,接下來設定 if 條件來讓他發出聲音
1 2 3 4 5 6 7 8 9 10
| function playHandler(e) {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`); if (audio) { audio.currentTime = 0; audio.play(); } }
|
DOM style
這樣一樣去抓取要跳出特效的 div 然後使用 if 條件去他去跑’playing’這個 class 而不是原來那個
1 2 3 4 5
| const dom = document.querySelector(`div[data-key="${e.keyCode}"]`);
if (dom) dom.classList.add('playing');
|
上面那行程式碼只做了讓他放大且變黃的特效,接下來要來處理放開之後變回原狀(class 要收掉)


一開始先選取所有的.key 的部分加入監聽之後使用transitionend
並加入函式transitionendHandler
1 2 3 4 5 6 7 8 9 10 11 12 13
|
document.querySelectorAll('.key').forEach(function (key) { key.addEventListener('transitionend', transitionendHandler) })
function transitionendHandler(e) { if (e.propertyName === 'transform') { e.currentTarget.classList.remove('playing') } }
|
下方這些東西是當 transition 效果結束之後會回傳的內容,在這裡我們就拿 propertyName = transform 這個來當指標,當 transform 出來(也就是 transition 結束,transitionend 被觸發時),把 .playing 這個 class 移除。
1 2 3
| function transitionendHandler(e) { console.log(e);
|

小補充
- data-* attribute 屬性:可自定義名稱
- keycode:每個鍵盤按鍵都有對應的 keycode
- es6 語法:箭頭函式、模板字串符(變數${})