人除了視覺的記憶以外,也有聽覺的記憶,Day25 我們已經讓方塊有了迷幻的動畫,並且點擊的時候可以發亮,今天我們希望除了發亮之外,點擊的時候也可以發出聲音。
所以第一件事情,我希望點擊的時候可以先抓到被點擊的方塊的 id。跟之前 Tic Tac Toe 井字棋
Day05 和貪吃蛇 Day20 一樣的手法,我分別給每一個方塊資料屬性(data-* attribute),data-id={blockId},把方塊的 id 存在 data-id 這個資料屬性裡面。
src/containers/MemoryBlocks/components/Block/index.js
<div
id={`block-${blockId}`}
data-id={blockId}
className="block__block-item"
onClick={handleOnClick}
/>
我們把函數 this.handleOnBlockClick 當做 props 傳進來,藉此來取得 data-id 的資料
src/containers/MemoryBlocks/index.js
<Block
key={block.get('id')}
blockId={block.get('id')}
sideLength={sideLength}
handleOnClick={this.handleOnBlockClick}
/>
如下程式碼,透過 getAttribute 我們可以拿到指定資料屬性(data-* attribute)資料屬性的值,也就是點擊哪個方塊,我們就可以拿到那一個方塊的 id。
src/containers/MemoryBlocks/index.js
const blockId = event.target.getAttribute('data-id');
拿到 id 之後,我們就可以來做兩件事情,一件事是把聲音播出來,另一件事是把答案存起來。
首先,我們來播放音樂,在 Day24 的時候,我們已經讓 blocks 這個陣列裡面,每個 block 都擁有它相對應的 Audio Object,我們現在要使用它,只要把它直接拿出來就可以了
src/containers/MemoryBlocks/index.js
const audioObject = blocks.getIn([blockId, 'audio'])();
拿到的這個 audioObject 內容如下:
audioObject = <audio preload="auto" src="https://awiclass.monoame.com/pianosound/set/1.wav"></audio>
這時候我們只要執行 audioObject.play(); 就可以把聲音播放出來了。但是值得一提的是,因為我們不想要每次播放的時候,都一直產生新的物件
,這樣有點浪費資源,所以當我們重複播放的時候,會把 currentTime 設為 0。
src/containers/MemoryBlocks/index.js
const blockId = event.target.getAttribute('data-id');
const audioObject = blocks.getIn([blockId, 'audio'])();
audioObject.currentTime = 0;
audioObject.play();
第二件事情,我們要把答案存起來,這樣我們之後就可以比對玩家回答是否正確。由於我們這邊是使用 React + Redux 的架構,所以我們要做的事情就是把取得的 block id 發一個 action 到 reducer 把它存起來就可以了。
所以在這個 onclick 之後所觸發的函式裡面,要同時播放音樂且把答案存起來,完整代碼如下:
src/containers/MemoryBlocks/index.js
handleOnBlockClick = (event) => {
const {
blocks,
handleUpdateAnswer,
} = this.props;
const blockId = event.target.getAttribute('data-id');
const audioObject = blocks.getIn([blockId, 'audio'])();
handleUpdateAnswer(parseInt(blockId, 10));
audioObject.currentTime = 0;
audioObject.play();
}
在 reducer 裡面,我們的作法如下
src/containers/MemoryBlocks/reducer.js
case UPDATE_ANSWER: {
const updatedAnswer = state.get('answer').push(action.payload);
return state.set('answer', updatedAnswer);
}
以下就是我們今天的成果,由於聲音有點難 demo ,所以這邊先印出來在螢幕上示意