---
# System prepended metadata

title: Music Player 實作
tags: [實作, javascript, CSS]

---

# Music Player 實作

###### tags: `實作` `CSS` `javascript`

[實作頁面連結](https://allenw0815.github.io/mission/mission_26/index.html)

![](https://i.imgur.com/FKmTHXY.png)




### Flowchart

1. 寫 HTML 結構
2. 寫 CSS，這實作比較複雜，應會用到偽元素以及 animate
3. 透過 JS 去讓 audio 播放以及暫停
4. 播放以及暫停時分別需要做哪些事情?
5. 讓進度條樣式對應到撥放的時間點上
 
> JS 流程

1.先把所需的 DOM 取好，用陣列存放歌曲名稱，畫面載入時依照陣列索引的名稱設定是哪首歌

```javascript=
const songs = ['Lost_in_paradise','Desperado','Wild_side','山雀','Yuve_Yuve_Yu']
let songIndex = 1

function loadingSong (song) {
    musicName.innerText = song.replaceAll('_',' ') //顯示歌名 替換掉不要的符號
    audio.src = `music/${song}.mp3` //找對應音源
    img.src = `img/${song}.png` //找對應圖片
}
loadingSong(songs[songIndex])
```
2.點擊播放鍵時，判斷是否正在撥放分別去做暫停及播放兩個相反的 function

```javascript=
const playingMode = () =>{
    audio.play() // 音源播放
    musicContainer.classList.add('play') // 替元素添加 class 來觸發 animate
    playBtn.querySelector('i').classList.remove('fa-play') // 移除當前圖示
    playBtn.querySelector('i').classList.add('fa-pause') // 更新圖示
}

function musicPlay() {
    const isPlaying = musicContainer.classList.contains('play') // 回傳 Boolean
    isPlaying ? pauseMode() : playingMode()
}
playBtn.addEventListener('click',musicPlay)
```

3.前後鍵點擊
```javascript=
function musicNext() {
    songIndex < songs.length -1  ? songIndex++ : songIndex // 限制在最後一首
    loadingSong(songs[songIndex]) // 更新歌曲
    playingMode() // 播放
}
nextBtn.addEventListener('click',musicNext)
```

4.監聽歌曲長度以及當前歌曲時間搭配 CSS 實現進度條動畫及點擊跳轉
```javascript=
function updateProgress(e) {
    // 這邊為解構賦值
    const {duration,currentTime} = e.srcElement // 取得總長跟播放到的長度
    const progressPercent = (currentTime / duration) * 100 // 取得百分比的數字
    progress.style.width = `${progressPercent}%` // 讓有顏色的進度條根據進度顯示
}
audio.addEventListener('timeupdate',updateProgress) // 音源播放時持續觸發
// 正確說法是 currentTime 變更時觸發，感覺很耗能應該可以壓低頻率

function setProgress(e) {
    const width = this.clientWidth // div的長度
    const x = e.offsetX // 點擊位置的長度
    const duration =  audio.duration
    audio.currentTime = ( x / width ) * duration
    // 代表點的位置是總長的幾分之幾再*總長就會得出相對應的當前播放時間然後更新currentTime
}
progressArea.addEventListener('click',setProgress)
```

5.歌曲結束後換下一首，就好比結束後觸發點擊下一首按鍵一樣
```javascript=
audio.addEventListener('ended',musicNext)
```


### 紀錄
* currentTime 播放時不停變更

 ![](https://i.imgur.com/syuAd08.png)

* 動畫可以使用多個效果
```css=
@keyframes rotate {
    0%{
        transform: rotate(0deg) scale(1);
    }
    50%{
        transform: rotate(180deg) scale(1.1);
    }
    100%{
        transform: rotate(360deg) scale(1);
    }
}
```

* 透過兩個重疊但顏色不同的元素，配合 JS 來實現進度條效果
```css=
.music-container .music-info .progress-area{
    width:80%;
    height: 5px;
    border-radius: 10px;   
    margin-bottom: 15px;
    background-color: rgb(235, 233, 233);
    cursor: pointer;
}
.music-container .music-info .progress-area .progress{
    background-color: rgb(145, 206, 245);
    height: 100%;
    border-radius: 10px;  
    width: 0%;
    transition: 0.1s linear;
}
```

* 透過添加 class 觸發 aninate 以及 進出場動畫

```css=
.img-container img{
    animation-play-state: paused;
}
/*  在最外層元素加上 play 讓動畫開始 */
.music-container.play .img-container img{
    animation-play-state: running;
}

.music-info{
    opacity:0;
    transition: .3s;
}
.music-container.play .music-info{
    opacity: 1;
    transform:translateY(100%);
}
```
* <font style="color:red">解構賦值</font>抓到對應的key

```javascript=
let {a,b,e} = {a: 10, b: 20, c: 30, d: 40, e:65}
a; // 10
b; // 10
c; // c is not defined
d; // d is not defined
e; // 10
```

[ES6 解構賦值](https://wcc723.github.io/javascript/2017/12/25/javascript-destructuring/)

### 小記

可以作一些補充
* 頁面上添加所有的歌單，直接點擊切換歌曲
* 加上音量功能
* 添加每首歌的秒數以及倒數
* 將旋轉的圖片改為前後各一張的 carousel 也可以透過這邊切歌曲

### 參考
[HTML\<audio><vedio>Property](https://www.w3school.com.cn/tags/html_ref_audio_video_dom.asp)
[timeupdate 事件](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLMediaElement/timeupdate_event)
