# JS練習_音樂播放器
建立一個音樂播放器使使用者能自由播放音樂,選取想要播放的音樂位置,調整音量及曲目。
## 成品頁面

## 成品功能
- 播放/ 暫停音樂
- 選擇前一首歌/ 下一首歌
- 使用者可以調整歌曲音量
- 根據總曲目數量,設定條件讓歌曲循環播放
- 設定進度條,使使用者決定歌曲的播放位置
## HTML
### audio
使用audio 標籤並放上src,讓網頁能夠輕鬆載入音樂檔
## css
### tranform: translate
透過給定目標位置距離起始元素的left(x座標)&top距離(y座標),使元素從其當前位置移動。
```.css
transform: translate(50px, 100px);
```
### width: 用來控制網頁元素寬度
- auto:自動判斷網頁元素的寬度。
- 數字+單位:可接受的單位有 px, em, cm 等網頁標準單位
- %:利用百分比設定網頁元素寬度,需要有比較的參考
- inherit:繼承自父層的寬度屬性值。(IE不支援)
### animation: 設定動畫
- animation 常見屬性:
- `animation-name`:動畫名稱
- `animation-duration`:動畫持續時間,預設 0,單位 s 或 ms。
- `animation-deplay`:動畫延遲播放時間,預設 0,單位 s 或 ms。
- `animation-play-state`:動畫播放或暫停狀態,預設 running。其他還有 paused。
- `animation-iteration-count`:動畫播放次數,預設 1。還有==infinite== 重複播放
- `animation-timing-function`:動畫加速度函式,預設 ease。其他還有: linear、ease-in、ease-out、ease-in-out,step-start、step-end、steps(int,start/end)、cubic-bezier(n,n,n,n)。
```.css=
/*----------可用縮寫--------------*/
animation:name duration | timing-function | delay | iteration-count | play-state;
```
- 在設定好動畫屬性時,設定關鍵影格 `keyframe`,可以使用 from...to... 也可以使用0%~100%設定
```.css
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
```
### z-index
- 利用z-index屬性,將選取的元素往上排列顯示,z-index值會大代表越上層。
- ==注意==使用z-index,其元素必須也設定position,不然z-index會沒效果。
```.css
.bg-image{
width: 100%;
height: 100vh;
position: absolute;
z-index: -1;
}
```
- [z-index小科普](https://developer.mozilla.org/zh-CN/docs/Web/CSS/z-index)
### object-fit
object-fit 屬性使元素去適應定義好寬高的<html標籤>。本次例子使用該屬性,讓歌曲圖片可以更適應容器
- 常見的屬性:
- fill: 預設的效果,也就是圖片會變得跟框框一樣大且若跟保留的框框比例不一樣會變形。
- contain: 圖片完整且剛好放進去。
- cover: 圖片剛好填滿。
- none: 圖片不做縮放但還是限制在框框的範圍。
```.css=
.bg-image img{
width: 100%;
height: 100vh;
filter: blur(6px);
top: 0;
left: 0;
object-fit: cover;
}
```
- [object-fit小科普](https://www.w3schools.com/css/css3_object-fit.asp)
## JS
實現步驟:
- 點擊按鈕播放歌曲,再次點擊按鈕,暫停歌曲。
- 點擊按鈕可選擇往前一首曲目或往後一首曲目。
- 利用音量進度條,調整曲目的音量。
- 利用歌曲進度條,調整曲目的不同資訊。
### loadSong()
- 將設定好的歌單及作者陣列作為參數執行函式
- 索引值要試先設定好,作為陣列索引值
- 利用`text()`方法顯示歌曲名稱/ 演唱者
- 設定歌曲的來源、圖片隨著陣列的索引值變動
```.js
function loadSong(song,a){
title.text(song);
artist.text(a);
audio.src = `music/${song}.mp3`;
cover.src = `images/${song}.jpg`;
bgCover.src = `images/${song}.jpg`;
}
```
### play() / pause()
1. 透過點擊button觸發播放歌曲函式,使其`addclass('play')`增加play屬性,`pause()`則是`removeClass`,帶入已設定好的css設定。
2. 透過 `find()`方法找到包含`('i.fas')`的元素。
3. 移除`('fa-play')`屬性
4. 增加`('fa-pause')`屬性
5. 利用`audio.play()`播放音樂,暫停音樂則是`audio.pause()`。
```.js=
function playSong(){
musicContainer.addClass('play')
playBtn.find('i.fas').removeClass('fa-play');
playBtn.find('i.fas').addClass('fa-pause');
audio.play();
}
```
### prevSong()/ nextSong()
1. 利用每點擊一次prevBtn,觸發函式,讓songIndex減一
2. 設定條件讓songIndex不會一直小下去,因為原本的歌曲陣列songIndex只有0、1、2
3. 執行`loadSong()`讓曲目圖片改變歌曲也改變
4. 執行`playSong()`播放歌曲
```.js
prevBtn.click(function(){
prevSong();
})
function prevSong(){
songIndex--;
//不然index會一直小下去但原本的index只有 0,1,2
if(songIndex< 0){
songIndex = songs.length -1
}
loadSong(songs[songIndex]);
playSong()
}
```
### setProgress()
目的:點擊進度條,可以選取所選歌曲的播放位置。
```.js
progressContainer.click(function(){
setProgress();
})
function setProgress(){
const width = this.clientWidth;
// console.log(width);
const clickX = e.offset().left;
// console.log(clickX);
const duration = audio.duration;
audio.currentTime = (clickX/width) *duration;
}
```
### timeupdate event
目的:隨著歌曲的播放更新進度條的寬度,以設置寬度百分比的方式顯示在progress bar。
- 觸發時點
- 播放video/ audio時,video/ audio的播放位置改變時。
- currentTime:
- currentTime屬性 ->讀取video/ audio的播放位置。
- duration:
- duration 屬性返回當前audio/ video的長度,以秒計算。
- progressPercent:
- 按照當前歌曲播放的進度佔總歌長的比例。
```.js=
// timeupdate event
$('#audio').on('timeupdate', function() {
const duration = $('#audio')[0].duration
const currentTime = $('#audio')[0].currentTime
const progressPercent = (currentTime / duration) * 100;
$('#progress').css('width', `${progressPercent}%`) /*% 不要忘記*/
})
```
###### tags: `javascript`