iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 2
1
Modern Web

實作經典 JavaScript 30系列 第 2

Day02:來做個鍵盤鼓手(一)

WES BOS系列影片
Alex快速導讀系列影片

Day01-JavaScript Drum Kit

思考需要的功能
1.按鍵按下後需要發出聲音
2.發出聲音的同時加上css樣式,結束後移除css樣式

實作重點:
1.利用自定義屬性名稱 data-key,讓鍵盤按鈕找到對應的聲音檔。
2.監聽keydown事件 - 讓按鈕按下後發出聲音
3.監聽transitionend事件 -利用transitionend事件取消css樣式

在這個實例中,[data-key]這個自定義屬性名稱非常重要,
為什麼會指定這些特定的數字呢?
那是因為每一個按鈕都有自己的keyCode,
我們可以利用監聽keydown事件來找到每個按鈕的keyCode。

window.addEventListener('keydown', function(e){
    console.log(e.keyCode)
})

印出 e.keyCode,發現e.keyCode就等於在HTML中寫好的[data-key]的值。
所以,利用這樣的唯一性,就可以找到對應的聲音檔,在鍵盤有keydown事件的條件下
設定audio這個變數,按下相對應的按鈕時,audio就代表該按鈕對應的聲音檔
例如: 按下 A ,A 的 keycode為 65 ,對應到的音檔就是 clap.wav

const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`)

但如果按了其他沒有設定在HTML上的按鈕,會找不到相對應的聲音檔,
因此需要加上一行code防止這個錯誤發生

if(!audio) return //如果沒有audio存在就終止這個function

有了對應的聲音檔,我們可以試試看讓對應的聲音檔撥放出來。

audio.play()

將這幾行程式碼組合起來,並用中文解釋
按下鍵盤按鈕 > 找到特定的audio檔案並撥放它

window.addEventListener('keydown', function(e){
  //console.log(e.keyCode)
  const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`)
  if(!audio) return
  audio.play()
})

做到這裡,發現連點同一個鍵盤按鈕的時候,聲音不會連續發出來,
這是因為每個聲音檔案的聲音長度大概都有2-3秒左右,
在整個聲音檔撥放完前,不會再撥放第二次。
解決的方法 => 每一次撥放前都將聲音檔倒回最開頭

audio.currentTime = 0

再來,為按鈕加上css樣式
作者很貼心的已經寫好樣式,就直接拿來用吧!
把注意力都放在寫JS上
觀察作者寫的css可以發現
.key => 目前所看到的樣式
.playing => 按鍵按下之後會顯示的樣式
所以現在的目標就是在按下按鈕時,
找出現在正按下的按鈕,並動態加入.playing的樣式

找出按鍵,一樣利用data-key的唯一性,我們就能夠得到現在按下的按鈕位置

const key = document.querySelector(`.key[data-key="${e.keyCode}"]`)

找到後添加.palying的樣式

key.classList.add('playing')

最終的程式碼為

window.addEventListener('keydown', function(e){
  //console.log(e.keyCode)
  const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`)
  const key = document.querySelector(`.key[data-key="${e.keyCode}"]`)
  if(!audio) return
  audio.currentTime = 0
  audio.play()
  key.classList.add('playing')
})

但是我們只加上了樣式,卻沒有移除它,所以樣式一直存在沒有消失
明天的目標就是解決這個問題。


上一篇
Day01:開賽廢言與自我介紹
下一篇
Day03:來做個鍵盤鼓手(二)
系列文
實作經典 JavaScript 3030
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言