iT邦幫忙

2021 iThome 鐵人賽

DAY 27
0
自我挑戰組

邊工作邊進行前端學習之旅系列 第 27

[Day 27] JS實作練習 - Music Player

  • 分享至 

  • xImage
  •  

前言

接下來幾天將以JS實作練習為主,提供製作方式的筆記,透過拆分各個項目的說明,能夠了解如何實現每項功能。在 JS 實作練習,每次一個小的項目就要花好幾個下班時間來完成,練習過程時常遇到不會的情況,一開始總是很緊張,會想自己怎會沒想到,還得去看課程給的製作方式才可以,但隨著實作練習增加,練習的語法更加熟練、精準的提問問題或是查找資料能力的提升,也讓後續實作練習上遇到問題時,減少焦慮感、並且能夠拆解問題慢慢解決它。

而在每次實作練習的進行方式大約會是,如果是完全不知該如何下手,會先看課程筆記下製作方式,接下來再換自己來撰寫功能 ; 但如果是大概知道要查詢什麼關鍵字或是相對應的文章有資訊可找,會先透過查到的資料自行製作,之後才會看課程。
課程連結

觀察須製作的功能

成品

  1. 播放器API的樣式
    <audio>: The Embed Audio element
  2. 音樂鍵的播放、暫停。並且要更改暫停鍵圖示、播放鍵的圖示
  3. 將音樂載入陣列,左右按鍵可以更換曲目。
  4. 點擊進度條,可以跳轉音樂位置。
  5. 隨音樂的轉換,更換版面的背景色彩。

各項拆解說明

1.音樂播放鍵(播放與停止)

  • 分別有兩個函式:playMusic()pauseMusic()
  • 在css設定.play的css,並於 js綁定事件,加入css的效果(使圖片如同轉盤,會旋轉)
  • 在icon的部分:在播放時:為暫停鍵圖示;在暫停時:為播放鍵的圖示
  • 透過play()pause(),讓音源播放與暫停。
  • 因為play()pause()是DOM元素,不是 jQuery 的 function,而要用 jQuery 取得DOM元素
    $('#audio').get(0).play() =>$('#audio')[0].play()
    $('#audio').get(0).pause() =>$('#audio')[0].pause()
//播放音樂
function playMusic() {

  $('.music-container').addClass('play');
  $('#play').find('i').removeClass('fa-play');
  $('#play').find('i').addClass('fa-pause');
  $('#audio').get(0).play();

};
//停止音樂
function pauseMusic() {
  $('.music-container').removeClass('play');
  $('#play').find('i').addClass('fa-play');
  $('#play').find('i').removeClass('fa-pause');
  $('#audio').get(0).pause();
}
  • 綁定事件:

如果音樂是播放狀態的話,就執行pauseMusic(),反之,音樂不處於播放時,執行playMusic()

 $('#play').click(function (e) {
    var hasPlay = $('#music-container').hasClass('play');
    //var a = $('#audio').paused;
    if (hasPlay) {
      pauseMusic();
    } else {
      playMusic();
    }
  });

參考資料:
How do I pull a native DOM element from a jQuery object?
Play/pause HTML 5 video using JQuery

2.載入音樂

  • 將歌曲名稱建立陣列,並將此回傳到建立的函式中
  • 設定預設的索引let songIndex = 1
  • 使用 attr( 屬性名, 屬性值 ),獲取屬性的值,在這部分,透過歌曲名稱來取得歌曲與照片
var songs_name = ['hey', 'summer', 'ukulele'];
let songIndex = 1;

function loadSongs(song) {
  //console.log(song);
  $('#title').text(song);
  
  $('#audio').attr('src', `music/${song}.mp3`);
  $('#cover').attr('src', `img/${song}.jpg`);
}

loadSongs(songs_name[songIndex]);
  • 查看函式回傳
loadSongs(songs_name);

  • 要抓取到該索引
loadSongs(songs_name[songIndex]);

3.左右鍵的跳轉

  • 下一首歌曲,與跳至前一首歌曲,兩個函式的撰寫有異曲同工之妙,只有在設條條件上的差異。
  • nextSong():設定條件為歌曲索引songIndex比 歌曲陣列長度-1 songs_name.length - 1還要小,我們就要將索引+1。
    • 例如這裏預設的索引為1,所以在點擊當下,判斷<songs_name.length - 1,所以需加1,讓索引變成2,跳至下一首 'ukulele'
  • prevSong():設定條件為歌曲索引songIndex比0大,就要索引-1,跳轉至上一首歌曲。若沒符合的話,索引就等於songs_name.length - 1
//歌曲的索引,如果比歌曲總數-1還小,就將索引加1,跳轉下一首
function nextSong() {
  if (songIndex < songs_name.length - 1) { songIndex += 1; } else {
    songIndex = 0
  };
  loadSongs(songs_name[songIndex]);
  playMusic();
}


//跳轉前一首
function prevSong() {
  //如果索引沒有大於0。就會播索引[2]
  if (songIndex > 0) { songIndex -= 1; } else {
    songIndex = songs_name.length - 1;
  };
  loadSongs(songs_name[songIndex]);
  playMusic();
}

參考資料:
Create a Music Player using JavaScript

4.點擊進度條,可以跳轉音樂位置

(1).顯示粉色進度條

  • duration:音源的時間(一樣是使用get方式取得)
  • currentTime:音樂播放的當前位置(以秒計)
  • progressBar:進度條
  • 計算百分比:(currentTime / duration) * 100
//顯示進度條
function handleProgress() {
  var duration = $('#audio').get(0).duration;
  //console.log(duration)
  var currentTime = $('#audio')[0].currentTime;
  //console.log(currentTime)
  const progressBar = $('#progress');
  const progressPercent = (currentTime / duration) * 100;

  //currentTime目前播放時間去與影片長度duration轉換成百分比,即可得到目前播放時間的百分比

  progressBar.css('width', `${progressPercent}%`);
};

(2).點擊進度條,會跳轉到該位置播放

  • width:獲取該進度條容器的寬度
  • 抓取點擊位置:
    • e.pageX:取得滑鼠在頁面裡的位置
    • elm.offset().left:絕對座標X軸
  • 將(點擊位置除以進度條的總長)乘以 音樂的時間長度,就可以取得點擊的時間位置theTime = ((xPos / width))* duration;
  • 最後現在時間設為計算好的點擊時間
//點擊進度條

//https://ithelp.ithome.com.tw/articles/10194871
//https://tools.wingzero.tw/article/sn/102


$('#progress-container').click(function (e) {
  const width = $('#progress-container').width(); //216.25
  //console.log(width);
  //取得點擊位置
  var elm = $(this);
  var xPos = e.pageX - elm.offset().left;

  //console.log(xPos);

  var duration = $('#audio')[0].duration;
  var theTime = ((xPos / width))
    * duration;
  //console.log(theTime);
  $('#audio')[0].currentTime = theTime;
});

執行過程,利用console來查看

console.log(e.pageX);
console.log(elm.offset().left);
console.log(xPos)

參考資料:
取得滑鼠位置、元素位置與區塊內的相對位置

5.歌曲播完後,換下一首

  $('#audio').on('ended',nextSong);

參考資料:
audio auto play next song when previous is finished

6.增加隨機的變換背景色彩

  • 色彩為0~256;而因為想取的較亮的色系,所以取64~256
    • Math.random() 會回傳一個偽隨機小數 (pseudo-random) 介於0到1之間(包含 0,不包含1)
    • Math.floor()會將所有的小數無條件捨去到比自身小的最大整數
    • Math.floor(Math.random() * 255) + 64就會取得64 to 256
  • 宣告變數bgColor為rdba(red,green,blue,a)
  • 最後將此函式,放入loadSongs()函式當中,每次播放、跳轉歌曲,同時背景顏色也會改變
function random_bg_color() {
  // Get a random number between 64 to 256 

  // (for getting lighter colors) 
  let red = Math.floor(Math.random() * 255) + 64;
  let green = Math.floor(Math.random() * 255) + 64;
  let blue = Math.floor(Math.random() * 255) + 64;
  let a = 0.5

  // Construct a color withe the given values 
  let bgColor = "rgba(" + red + ", " + green + ", " + blue + ", " + a + ")";

  var bg = $(document.body).css('background', `${bgColor}`);
  // Set the background to the new color 
  bg = bgColor;
  console.log(bg)

} 

參考資料:
Create a Music Player using JavaScript
Won't Math.floor(Math.random() * 255) generate uneven probabilities?
[筆記][JavaScript]用Math.random()取得亂數的技巧


上一篇
[Day 26] JS實作 - expense tracker 記帳簿
下一篇
[Day 28] JS實作練習 - Scroll Blog無限捲動
系列文
邊工作邊進行前端學習之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言