JavaScript30之打擊鼓

語雀地址:?https://www.yuque.com/javascript30/article/drumkit
hi,我是木易,關(guān)于我上傳搬運js30的視頻,已經(jīng)快有三年了,沒想到過了這么久,依然有人通過學習小組來添加我的學習交流群,我還是有一點感慨的。
由于之前的視頻沒有中文字幕,我決定今年重新將js30的視頻制作一遍,加上動畫與解說
但是視頻的工作量太大,為了給小伙伴們更好的體驗,我決定先編寫js30的解析寫好思路,再制作視頻。
本片文章是js30的第一個項目:打擊鼓
實現(xiàn)效果
模擬一個打鼓的頁面。用戶在鍵盤上按下 ASDFGHJKL 這幾個鍵時,頁面上與字母對應的按鈕變大變亮,并播放對應的鼓點聲音

技術(shù)分析
按下鍵盤(監(jiān)聽鍵盤事件)
對應的按鈕變大變變亮(改變按鍵css樣式)
播放鼓點聲音(控制對應的audio標簽播放聲音)
實現(xiàn)步驟
1. 通過鍵盤事件 keydown 獲取對應的元素
? 我們首先來監(jiān)聽 keydown 事件,實現(xiàn)按下按鍵打印出對應的元素(按鍵和audio元素)
原版課程中作者使用 keyCode 來獲取對應的元素,現(xiàn)在已經(jīng)不推薦這樣做了
KeyboardEvent.keyCode 可以獲取對應的按鍵 Unicode 編碼,但是該屬性已棄用,推薦使用 KeyboardEvent.code

這里我們使用 code 來獲取對應的元素

現(xiàn)在我們按下 A 會打印出這樣的結(jié)果

2. 播放聲音
? 獲取對應的 audio 元素后,我們來使用 play()方法 播放對應的鼓聲,這里我們使用了 currentTime 來實現(xiàn)連續(xù)按下按鍵連續(xù)播放的效果,如果不加 currentTime = 0,默認播放有類似節(jié)流的效果
currentTime 是 AudioContext 的一個只讀屬性,返回表示只增不減的硬件時間戳的雙精度浮點數(shù),可以用來控制音頻回放,實現(xiàn)可視化時間軸等等。該值從 0 開始。

? 現(xiàn)在如果我們按下A~L 以外的按鍵會控制臺會報錯,我們需要加一些約束條件,當我們沒有獲取到對應的元素時就退出鍵盤事件

? 添加對應的邏輯判斷

3. 按下鍵盤時改變對應的鍵盤樣式
? 當按下鍵盤時就給對應的盒子添加對應的樣式,這里是定義了一個 playing類選擇器, 并給對應的盒子添加 transition 動畫來實現(xiàn)相應的效果

? 按下鍵盤時就添加 playing樣式,動畫結(jié)束時就移除 playing樣式,這里我們有三種做法
監(jiān)聽 audio 結(jié)束
? 當 audio 播放結(jié)束時我們移除樣式

定時器控制樣式
根據(jù)動畫時長來控制樣式
? 我們知道動畫持續(xù)時間是70ms

? 添加定時器,觸發(fā)事件時我們就添加定時器移除樣式,觸發(fā)事件很頻繁時可能看不到樣式就移除了,所以我們在觸發(fā)事件時先移除定時器,再添加一個定時器

transitionend事件控制樣式
? 獲取所有的 鍵盤元素 然后添加 transitionend 事件,動畫結(jié)束時移除對應樣式

? transitionend 會觸發(fā)多次,為了避免多次執(zhí)行去除樣式的操作,我們可以添加對應的約束條件,減少去除樣式的次數(shù)

? 注意不要通過 transform 或 box-shadow 進行判斷,這樣會導致頻繁觸發(fā)樣式無法消失,暫不清楚bug來源


? 進行如下配置將沒有上述 bug

完整代碼
? 這里給出最后一種實現(xiàn)方式的代碼
? 將代碼進行一些封裝
其他效果實現(xiàn)
? 如果我們想要按下后播放一次的效果(不頻繁播放),可以定義一個開關(guān)來實現(xiàn)
資料和練習素材都在群里:943158724