[Day 27] JS实作练习 - Music Player

前言

接下来几天将以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()取得乱数的技巧


<<:  [Day13] Flutter with GetX qr_flutter & qr_code_scanner

>>:  Day27 ( 高级 ) 小画家 ( 舞台上画图 )

Re: 新手让网页 act 起来: Day24 - React Hooks 之 useMemo

前言 昨天我们介绍过如何使用 React.memo 与 useCallback 来做效能优化,而 u...

[Day 22] Leetcode 437. Path Sum III (C++)

前言 今天这题也是TOP 100 Liked中的题目─437. Path Sum III,是昨天最後...

故事二十七:遇到不同情况,都是练习的好机会!

     延续昨天的实作,今天继续研究一下大学学生人数的近况。   之前,我们曾经使用 csv 档实...

Day 21 - SwiftUI开发学习5(文字填入)

今天我们来学习如何使用填入文字的物件 正文 文字填入 TextField 可以将文字填入进去。 如果...

Day 18 Rails MVC

What is MVC? 先招唤 wiki 大大出来解释一下 MVC 是甚麽: MVC模式(Mode...