主題
透過JS使鍵盤按下後播放出對應按鍵的聲音,並同時產生一個特效,
在按下其他鍵後會關閉該特效並於新按鍵中啟用。
步驟
Step1. 新增keydown listener
利用window.addEventListener('keydown', playSound);
來監聽鍵盤動作。
Step2. 建立functionplaySound
- 利用傳入的e.keyCode來取得對應的
audio
標籤及該按鍵的div
標籤 - 判斷傳入的e.keyCode是否有對應的
audio
標籤,若無則退出 - 使對應的
div
加上playing
樣式,產生對應的典及特效 - 使對應的
audio
播放時間為0 - 播放對應的音檔
Step3. 新增transitionend listener
- 偵測所有包含
className='key'
的元件 - 當該元件觸發特效並結束時(
transitionend
),呼叫removeTransition
Step4. 建立functionremoveTransition
- 判斷傳入的propretyName是否為transform,若否則退出
- 若為transform,則移除
playing
樣式
JavaScript語法&備註
element.classList
這個會回傳element的class值(陣列),
範例用到了classList的方法add()
及remove()
1
2classList.add('aaa', 'bbb', 'ccc'); //新增多個className
classList.remove('aaa', 'bbb', 'ccc'); //移除多個className
如果已經存在/不存在的className則會被忽略。
還有其他方法如:
toggle()
偵測是否存在這個className,存在則刪除/不存在則新增contains()
偵測是否存在這個className, 返回true/false
參閱:MDN-Element.classList
HTMLmediaElement(audio)
HTML的audio
標籤,在HTML放置如下標籤指定音源1
<audio src="sound/a.mp3"></audio>
透過javascript來操作:element.play()
:進行播放element.currentTime
:指定播放秒數
範例中使用currentTime
是為了達到連發的效果XD
forEach
之前沒在javascript中使用的語法,用法如下:1
arr.forEach(callback function)
我是用for迴圈來比對做語法理解的:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20let datas = ['data1', 'data2', 'data3'];
//for迴圈寫法
for (let i = 0; i < datas.length; i++) {
console.log(datas[i]);
}
//forEach寫法
datas.forEach(function(data){
console.log(data);
});
//都會輸出
//data1
//data2
//data3
datas.forEach(console.log);
//如果透過上面直接console.log來看到結果是:
//data1 0 ["data1", "data2", "data3"]
//data2 1 ["data1", "data2", "data3"]
//data3 2 ["data1", "data2", "data3"]
//回傳的分別是value, index, array本身內容。
箭頭函式(Arrow Function)
ES6的新語法1
2
3
4
5
6//傳統寫法
let func1 = function(arg) { console.log('Hi, ' + arg); };
//箭頭函式寫法
let func2 = arg => console.log('Hi, ' + arg);
//補充:如果該function沒有參數要傳,要帶空括號如下
let func3 = () => console.log('Hi');
addEventListener
因為我是是第一次看到transtionend
這個event,
所以去MDN查了HTML DOM event記錄連結在此
template literals
模板文字,同樣屬於第一次看到的東西,
利用`
- 反引號(back-tick)或稱重音符(grave accent)來組合字串,
在範圍內可利用${}
加上變數操作
例如原本的字串+變數組合寫法:1
2
3let str = '<div data-key="' + key + '">' +
'<button>click me</button>' +
'</div>';
改用template string來做只要1
2
3let str = `<div data-key="${key}">
<button>click me</button>
</div>`;
用`
包住字串,利用${}
來包變數
這樣可以很輕鬆的組出易於閱讀的組合字串!
不用像以前還要注意單雙引號與+的配合了~
Array.from
範例中有這段1
const keys = Array.from(document.querySelectorAll('.key'));
查詢了Array.from
才知道這是一個將一個物件或是字串轉為陣列格式的語法,
但當時覺得為何要把陣列在轉成陣列?querySelectorAll不就是返回陣列嗎?
在查下去才發現querySelectorAll返回的是nodeList且nodeList跟Array是不同的!
雖然都很像陣列,但nodeList並沒有array.prototype上的方法!
最簡單的例子是用array.push()去測試,會發現由querySelectAll得到的物件無法用.push()。1
2
3
4
5let testNodeList = document.querySelectAll('.key');
testNodeList.push('add'); // <--非陣列會報錯TypeError: testNodeList.push is not a function
let testArray = Array.from(testNodeList);
testArray.push('add'); // <-- 轉為陣列就可以了
至於在範例中轉型的原因,
我想應該是因為若無轉型為Array使用nodeList來forEach可能會導致某些瀏覽器版本錯誤。
nodeList由querySelectorAll及childNodes返回的
參閱:MDN-NodeList
CSS語法&備註
display:flex
CSS3的排版語法,以範例中的來做備註紀錄1
2
3
4
5
6
7.keys {
display: flex; /*要使用flex要在元素內先宣告flex*/
flex: 1; /*這是一個簡寫,全部為flex: flex-grow|flex-shrink|flex-basis*/
min-height: 100vh; /*vh代表view height, 百分比呈現*/
align-items: center; /*宣告為flex後才有效的屬性,垂直置中*/
justify-content: center;/*宣告為flex後才有效的屬性,水平置中*/
}
參閱:MDN-flex
探索
原範例只能由鍵盤觸發,
我的探索是為這個範例加上可由滑鼠點擊觸發的功能1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const keys = Array.from(document.querySelectorAll('.key'));
//新增click功能綁定至每個class="key"
keys.forEach(key => key.addEventListener('click', playSound));
function playSound(e) {
//依據不同的事件來取得對應的key_code(e.type可以看,以下是簡寫版)
let keyCode = e.keyCode || this.getAttribute('data-key');
const audio = document.querySelector(`audio[data-key="${keyCode}"]`);
const key = document.querySelector(`div[data-key="${keyCode}"]`);
if (!audio) return;
key.classList.add('playing');
audio.currentTime = 0;
audio.play();
}