這個小專案是來自https://javascript30.com/的教學,看完教學影片後自己嘗試實作後的結果,無意見在國外論壇看到這個JS30 沒想到還挺有趣的 也是完全免費的資源,有時間的話真的可以試試看~! 先附上程式碼的部分,由於是看完影片後重頭做起的,內容會與示範的不太一樣。
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Drum kit</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="keys"> <div class="key" data-key="65"> <kbd>A</kbd> </div> <div class="key" data-key="83"> <kbd>S</kbd> </div> <div class="key" data-key="68"> <kbd>D</kbd> </div> <div class="key" data-key="70"> <kbd>F</kbd> </div> <div class="key" data-key="71"> <kbd>G</kbd> </div> <div class="key" data-key="72"> <kbd>H</kbd> </div> <button class='play'> Play the music </button> </div> <audio src="./sounds/clay.mp3" data-key="65"></audio> <audio src="./sounds/bubbles.mp3" data-key="83"></audio> <audio src="./sounds/confetti.mp3" data-key="68"></audio> <audio src="./sounds/ufo.mp3" data-key="70"></audio> <audio src="./sounds/moon.mp3" data-key="71"></audio> <audio src="./sounds/glimmer.mp3" data-key="72"></audio> <script src="main.js"></script> </body> </html>
CSS
body {
background-image: url('https://upload.cc/i1/2019/05/21/LsQHYB.jpg');
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
}
.keys {
display: flex;
justify-content: center;
align-items: center;
height: 800px;
width: 100%;
position: relative;
bottom:40px;
}
.key {
border: 2px solid black;
width: 40px;
margin: 6px;
text-align: center;
transition: all 0.07s;
background: rgba(0, 0, 0, 0.4);
text-align: center;
}
.playing {
transform: scale(1.2);
border-color: chocolate;
box-shadow:0 0 10px #ffc600;
}
kbd {
display: block;
font-size: 30px;
color: white;
}
span {
color: yellow;
}
Javascript
let empty = []
window.addEventListener('keydown', function (e) {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);
audio.currentTime = 0;//點擊後將音訊退回開頭
audio.play();
key.classList.add('playing');
empty.push(e.keyCode)
})
function removeTransition(e) {
if (e.propertyName != 'transform') return;
this.classList.remove('playing');
}
function playTheMusic(arr) {
arr.forEach(music => {
const musics = document.querySelector(`audio[data-key="${music}"]`);
musics.currentTime = 0;
musics.play();
setTimeout('console.log("test123");', 3000);
})
}
const keys = document.querySelectorAll('.key')
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
//播放歌曲,此為未完成的功能
const play = document.querySelector('.play')
play.addEventListener('click', function () {
playTheMusic(empty);
});
學習重點
- 善用data-* attribute方便後續的元素選取。
- 利用 http://keycode.info/ 可以查出每個鍵對應的key-code
- 利用.play()播放audio音訊,但由於連續點擊時會發現每段音訊完整播放完後才能播放下一次音訊,解決的方法便是加入.currentTime = 0 讓每次點擊時該音訊rewind回到開頭。
- 在每一次點擊時,對應的按鈕會放大(transform:scale)並改變邊框顏色,但我們預期的效果是點擊後要迅速恢復原狀。這時候我們會需要在每一個key上面加上監聽器(利用forEach處理Node List),此時的事件類型為’transitionend’ 也就是每次變換結束後便會觸發接下來的函式,那要如何判定一個元素已經完成轉換? 需要檢查該元素的propertyName == ‘transform’。
- 未完成的功能為:建立一個空陣列儲存每次點擊的key-code,點擊播放按鈕後播放出使用者剛剛製作的歌曲,但目前卡在所有音訊會在同一時間播放。
最終成品
