原生JS實(shí)現(xiàn)音樂播放器的示例代碼
本文主要介紹了原生JS實(shí)現(xiàn)音樂播放器的示例代碼,分享給大家,具體如下:
效果圖

音樂播放器
- 播放控制
- 播放進(jìn)度條控制
- 歌詞顯示及高亮
- 播放模式設(shè)置
播放器屬性歸類
按照播放器的功能劃分,對(duì)播放器的屬性和DOM元素歸類,實(shí)現(xiàn)同一功能的元素和屬性保存在同一對(duì)象中,便于管理和操作
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'),
...
}
播放控制
功能:控制音樂的播放和暫停,上一首,下一首,播放完成及相應(yīng)圖標(biāo)修改
audio所用API:audio.play() 和 audio.pause()和audio ended事件
// 音樂的播放和暫停,上一首,下一首控制
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) {
//音樂播放,更改圖標(biāo)及開啟播放動(dòng)畫
play.classList.remove('songStop');
play.classList.add('songStart');
control.albumCover.classList.add('albumRotate');
control.albumCover.style.animationPlayState = 'running';
} else {
//音樂暫停,更改圖標(biāo)及暫停播放動(dòng)畫
...
}
}
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
// 播放進(jìn)度實(shí)時(shí)更新
audioFile.file.addEventListener('timeupdate', lyricAndProgressMove);
// 通過拖拽調(diào)整進(jìn)度
control.progressDot.addEventListener('click', adjustProgressByDrag);
// 通過點(diǎn)擊調(diào)整進(jìn)度
control.progressWrap.addEventListener('click', adjustProgressByClick);
播放進(jìn)度實(shí)時(shí)更新:通過修改相應(yīng)DOM元素的位置或者寬度進(jìn)行修改
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)度:通過拖拽移動(dòng)進(jìn)度條,并且同步更新歌曲播放進(jìn)度
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)整:通過點(diǎn)擊進(jìn)度條,并且同步更新歌曲播放進(jìn)度
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)前歌詞(通過添加樣式)
audio所用API:audio timeupdate事件,audio.currentTime
// 歌詞顯示實(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:無
// 播放模式設(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)音樂播放器的示例代碼的文章就介紹到這了,更多相關(guān)JS 音樂播放器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS密碼生成與強(qiáng)度檢測(cè)完整實(shí)例(附demo源碼下載)
這篇文章主要介紹了JS密碼生成與強(qiáng)度檢測(cè)完整實(shí)例,涉及JavaScript密碼的生成,破解時(shí)間計(jì)算,密碼安全監(jiān)測(cè)及大小寫鎖定判斷等功能的實(shí)現(xiàn)技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2016-04-04
javascript-hashchange事件和歷史狀態(tài)管理實(shí)例分析
這篇文章主要介紹了javascript-hashchange事件和歷史狀態(tài)管理,結(jié)合實(shí)例形式分析了javascript-hashchange基本功能、原理及歷史狀態(tài)管理相關(guān)操作技巧,需要的朋友可以參考下2020-04-04
js實(shí)現(xiàn)表單項(xiàng)的全選、反選及刪除操作示例
這篇文章主要介紹了js實(shí)現(xiàn)表單項(xiàng)的全選、反選及刪除操作,結(jié)合實(shí)例形式分析了基于dedecms后臺(tái)使用js實(shí)現(xiàn)表單項(xiàng)的全選、反選及刪除相關(guān)操作技巧,需要的朋友可以參考下2020-06-06
JavaScript顯示當(dāng)然日期和時(shí)間即年月日星期和時(shí)間
使用js顯示當(dāng)然日期和時(shí)間在網(wǎng)頁中很是常見,方法有很多,不過多說大同小異,下面有個(gè)不錯(cuò)的示例,需要的朋友可以感受下2013-10-10
js防抖函數(shù)和節(jié)流函數(shù)使用場(chǎng)景和實(shí)現(xiàn)區(qū)別示例分析
這篇文章主要介紹了js防抖函數(shù)和節(jié)流函數(shù)使用場(chǎng)景和實(shí)現(xiàn)區(qū)別,結(jié)合實(shí)例形式詳細(xì)分析了js防抖函數(shù)和節(jié)流函數(shù)基本功能、定義、用法區(qū)別及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04
作為一名優(yōu)秀的接口調(diào)用工程師,對(duì)接口的返回信息進(jìn)行校驗(yàn)是必不可少的,本文整理的是一些常用的校驗(yàn)方式,希望能夠?qū)Υ蠹矣兴鶐椭?/div> 2023-05-05最新評(píng)論

