本文主要介紹了原生JS實(shí)現(xiàn)音樂(lè)播放器的示例代碼,分享給大家,具體如下:
效果圖
音樂(lè)播放器
- 播放控制
- 播放進(jìn)度條控制
- 歌詞顯示及高亮
- 播放模式設(shè)置
播放器屬性歸類(lèi)
按照播放器的功能劃分,對(duì)播放器的屬性和DOM元素歸類(lèi),實(shí)現(xiàn)同一功能的元素和屬性保存在同一對(duì)象中,便于管理和操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
const control = { //存放播放器控制 play: document.querySelector( '#myplay' ), ... index: 2, //當(dāng)前播放歌曲序號(hào) ... } const audioFile = { //存放歌曲文件及相關(guān)信息 file: document.getElementsByTagName( 'audio' )[0], currentTime: 0, duration: 0, } const lyric = { // 歌詞顯示欄配置 ele: null , totalLyricRows: 0, currentRows: 0, rowsHeight: 0, } const modeControl = { //播放模式 mode: [ '順序' , '隨機(jī)' , '單曲' ], index: 0 } const songInfo = { // 存放歌曲信息的DOM容器 name: document.querySelector( '.song-name' ), ... } |
播放控制
功能:控制音樂(lè)的播放和暫停,上一首,下一首,播放完成及相應(yīng)圖標(biāo)修改
audio所用API:audio.play() 和 audio.pause()和audio ended事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
// 音樂(lè)的播放和暫停,上一首,下一首控制 control.play.addEventListener( 'click' ,()=>{ control.isPlay = !control.isPlay; playerHandle(); } ); control.prev.addEventListener( 'click' , prevHandle); control.next.addEventListener( 'click' , nextHandle); audioFile.file.addEventListener( 'ended' , nextHandle); function playerHandle() { const play = control.play; control.isPlay ? audioFile.file.play() : audioFile.file.pause(); if (control.isPlay) { //音樂(lè)播放,更改圖標(biāo)及開(kāi)啟播放動(dòng)畫(huà) play.classList.remove( 'songStop' ); play.classList.add( 'songStart' ); control.albumCover.classList.add( 'albumRotate' ); control.albumCover.style.animationPlayState = 'running' ; } else { //音樂(lè)暫停,更改圖標(biāo)及暫停播放動(dòng)畫(huà) ... } } function prevHandle() { // 根據(jù)播放模式重新加載歌曲 const modeIndex = modeControl.index; const songListLens = songList.length; if (modeIndex == 0) { //順序播放 let index = --control.index; index == -1 ? (index = songListLens - 1) : index; control.index = index % songListLens; } else if (modeIndex == 1) { //隨機(jī)播放 const randomNum = Math.random() * (songListLens - 1); control.index = Math.round(randomNum); } else if (modeIndex == 2) { //單曲 } reload(songList); } function nextHandle() { const modeIndex = modeControl.index; const songListLens = songList.length; if (modeIndex == 0) { //順序播放 control.index = ++control.index % songListLens; } else if (modeIndex == 1) { //隨機(jī)播放 const randomNum = Math.random() * (songListLens - 1); control.index = Math.round(randomNum); } else if (modeIndex == 2) { //單曲 } reload(songList); } |
播放進(jìn)度條控制
功能:實(shí)時(shí)更新播放進(jìn)度,點(diǎn)擊進(jìn)度條調(diào)整歌曲播放進(jìn)度
audio所用API:audio timeupdate事件,audio.currentTime
1
2
3
4
5
6
|
// 播放進(jìn)度實(shí)時(shí)更新 audioFile.file.addEventListener( 'timeupdate' , lyricAndProgressMove); // 通過(guò)拖拽調(diào)整進(jìn)度 control.progressDot.addEventListener( 'click' , adjustProgressByDrag); // 通過(guò)點(diǎn)擊調(diào)整進(jìn)度 control.progressWrap.addEventListener( 'click' , adjustProgressByClick); |
播放進(jìn)度實(shí)時(shí)更新:通過(guò)修改相應(yīng)DOM元素的位置或者寬度進(jìn)行修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function lyricAndProgressMove() { const audio = audioFile.file; const controlIndex = control.index; // 歌曲信息初始化 const songLyricItem = document.getElementsByClassName( 'song-lyric-item' ); if (songLyricItem.length == 0) return ; let currentTime = audioFile.currentTime = Math.round(audio.currentTime); let duration = audioFile.duration = Math.round(audio.duration); //進(jìn)度條移動(dòng) const progressWrapWidth = control.progressWrap.offsetWidth; const currentBarPOS = currentTime / duration * 100; control.progressBar.style.width = `${currentBarPOS.toFixed(2)}%`; const currentDotPOS = Math.round(currentTime / duration * progressWrapWidth); control.progressDot.style.left = `${currentDotPOS}px`; songInfo.currentTimeSpan.innerText = formatTime(currentTime); } |
拖拽調(diào)整進(jìn)度:通過(guò)拖拽移動(dòng)進(jìn)度條,并且同步更新歌曲播放進(jìn)度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
function adjustProgressByDrag() { const fragBox = control.progressDot; const progressWrap = control.progressWrap drag(fragBox, progressWrap) } function drag(fragBox, wrap) { const wrapWidth = wrap.offsetWidth; const wrapLeft = getOffsetLeft(wrap); function dragMove(e) { let disX = e.pageX - wrapLeft; changeProgressBarPos(disX, wrapWidth) } fragBox.addEventListener( 'mousedown' , () => { //拖拽操作 //點(diǎn)擊放大方便操作 fragBox.style.width = `14px`;fragBox.style.height = `14px`;fragBox.style.top = `-7px`; document.addEventListener( 'mousemove' , dragMove); document.addEventListener( 'mouseup' , () => { document.removeEventListener( 'mousemove' , dragMove); fragBox.style.width = `10px`;fragBox.style.height = `10px`;fragBox.style.top = `-4px`; }) }); } function changeProgressBarPos(disX, wrapWidth) { //進(jìn)度條狀態(tài)更新 const audio = audioFile.file const duration = audioFile.duration let dotPos let barPos if (disX < 0) { dotPos = -4 barPos = 0 audio.currentTime = 0 } else if (disX > 0 && disX < wrapWidth) { dotPos = disX barPos = 100 * (disX / wrapWidth) audio.currentTime = duration * (disX / wrapWidth) } else { dotPos = wrapWidth - 4 barPos = 100 audio.currentTime = duration } control.progressDot.style.left = `${dotPos}px` control.progressBar.style.width = `${barPos}%` } |
點(diǎn)擊進(jìn)度條調(diào)整:通過(guò)點(diǎn)擊進(jìn)度條,并且同步更新歌曲播放進(jìn)度
1
2
3
4
5
6
7
8
|
function adjustProgressByClick(e) { const wrap = control.progressWrap; const wrapWidth = wrap.offsetWidth; const wrapLeft = getOffsetLeft(wrap); const disX = e.pageX - wrapLeft; changeProgressBarPos(disX, wrapWidth) } |
歌詞顯示及高亮
功能:根據(jù)播放進(jìn)度,實(shí)時(shí)更新歌詞顯示,并高亮當(dāng)前歌詞(通過(guò)添加樣式)
audio所用API:audio timeupdate事件,audio.currentTime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// 歌詞顯示實(shí)時(shí)更新 audioFile.file.addEventListener( 'timeupdate' , lyricAndProgressMove); function lyricAndProgressMove() { const audio = audioFile.file; const controlIndex = control.index; const songLyricItem = document.getElementsByClassName( 'song-lyric-item' ); if (songLyricItem.length == 0) return ; let currentTime = audioFile.currentTime = Math.round(audio.currentTime); let duration = audioFile.duration = Math.round(audio.duration); let totalLyricRows = lyric.totalLyricRows = songLyricItem.length; let LyricEle = lyric.ele = songLyricItem[0]; let rowsHeight = lyric.rowsHeight = LyricEle && LyricEle.offsetHeight; //歌詞移動(dòng) lrcs[controlIndex].lyric.forEach((item, index) => { if (currentTime === item.time) { lyric.currentRows = index; songLyricItem[index].classList.add( 'song-lyric-item-active' ); index > 0 && songLyricItem[index - 1].classList.remove( 'song-lyric-item-active' ); if (index > 5 && index < totalLyricRows - 5) { songInfo.lyricWrap.scrollTo(0, `${rowsHeight * (index - 5)}`) } } }) } |
播放模式設(shè)置
功能:點(diǎn)擊跳轉(zhuǎn)播放模式,并修改相應(yīng)圖標(biāo)
audio所用API:無(wú)
1
2
3
4
5
6
7
8
9
10
11
12
|
// 播放模式設(shè)置 control.mode.addEventListener( 'click' , changePlayMode); function changePlayMode() { modeControl.index = ++modeControl.index % 3; const mode = control.mode; modeControl.index === 0 ? mode.setAttribute( "class" , "playerIcon songCycleOrder" ) : modeControl.index === 1 ? mode.setAttribute( "class" , "playerIcon songCycleRandom " ) : mode.setAttribute( "class" , "playerIcon songCycleOnly" ) } |
代碼地址:https://github.com/hcm083214/audio-player
到此這篇關(guān)于原生JS實(shí)現(xiàn)音樂(lè)播放器的示例代碼的文章就介紹到這了,更多相關(guān)JS 音樂(lè)播放器內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://juejin.cn/post/6932662088250687501