最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 原生JS实现音乐播放器

    正文概述 掘金(单线程_01)   2021-02-24   278

    项目预览

    代码地址:github.com/hcm083214/a…

    原生JS实现音乐播放器

    音乐播放器

    • 播放控制
    • 播放进度条控制
    • 歌词显示及高亮
    • 播放模式设置

    播放器属性归类

    按照播放器的功能划分,对播放器的属性和DOM元素归类,实现同一功能的元素和属性保存在同一对象中,便于管理和操作

    const control = { //存放播放器控制
        play: document.querySelector('#myplay'),
    	...
        index: 2,//当前播放歌曲序号
    	...
    }
    
    const audioFile = { //存放歌曲文件及相关信息
        file: document.getElementsByTagName('audio')[0],
        currentTime: 0,
        duration: 0,
    }
    
    const lyric = { // 歌词显示栏配置
        ele: null,
        totalLyricRows: 0,
        currentRows: 0,
        rowsHeight: 0,
    }
    
    const modeControl = { //播放模式
        mode: ['顺序', '随机', '单曲'],
        index: 0
    }
    
    const songInfo = { // 存放歌曲信息的DOM容器
        name: document.querySelector('.song-name'),
    	...
    }
    

    播放控制

    功能:控制音乐的播放和暂停,上一首,下一首,播放完成及相应图标修改

    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) {
    		//音乐播放,更改图标及开启播放动画
            play.classList.remove('songStop');
            play.classList.add('songStart');
            control.albumCover.classList.add('albumRotate');
            control.albumCover.style.animationPlayState = 'running';
        } else {
            //音乐暂停,更改图标及暂停播放动画
    		...
        }
    }
    
    
    function prevHandle() {    // 根据播放模式重新加载歌曲
        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) {//随机播放
            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) {//随机播放
            const randomNum = Math.random() * (songListLens - 1);
            control.index = Math.round(randomNum);
        } else if (modeIndex == 2) {//单曲
        }
        reload(songList);
    }
    

    播放进度条控制

    功能:实时更新播放进度,点击进度条调整歌曲播放进度

    audio所用API:audio timeupdate事件,audio.currentTime

    // 播放进度实时更新
    audioFile.file.addEventListener('timeupdate', lyricAndProgressMove);
    // 通过拖拽调整进度
    control.progressDot.addEventListener('click', adjustProgressByDrag);
    // 通过点击调整进度
    control.progressWrap.addEventListener('click', adjustProgressByClick);
    

    播放进度实时更新:通过修改相应DOM元素的位置或者宽度进行修改

    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);
    
        //进度条移动
        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);
    
    }
    

    拖拽调整进度:通过拖拽移动进度条,并且同步更新歌曲播放进度

    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', () => { //拖拽操作
            //点击放大方便操作
            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) { //进度条状态更新
        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}%`
    }
    

    点击进度条调整:通过点击进度条,并且同步更新歌曲播放进度

    function adjustProgressByClick(e) {
    
        const wrap = control.progressWrap;
        const wrapWidth = wrap.offsetWidth;
        const wrapLeft = getOffsetLeft(wrap);
        const disX = e.pageX - wrapLeft;
        changeProgressBarPos(disX, wrapWidth)
    }
    

    歌词显示及高亮

    功能:根据播放进度,实时更新歌词显示,并高亮当前歌词(通过添加样式)

    audio所用API:audio timeupdate事件,audio.currentTime

    // 歌词显示实时更新
    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;
        //歌词移动
        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)}`)
                }
    
            }
        })
    }
    

    播放模式设置

    功能:点击跳转播放模式,并修改相应图标

    audio所用API:无

    // 播放模式设置
    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")
    }
    

    起源地下载网 » 原生JS实现音乐播放器

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元