写一个音乐播放器1--歌曲播放进度条

1,666 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

歌曲播放进度条效果图

首先先上效果图吧,基于Vue2实现了一个基础的音乐播放进度条,左侧为歌曲已播放时长,右侧为歌曲总时长,进度条蓝色部分为已播放部分。

进度条.png

实现

html布局部分

  • 采用原生audio来实现音乐播放功能;
  • 进度条主体是由一个类名为progress-bar的父盒子包裹一个类名为blue-bar的子盒子,其中父盒子为底部灰色进度条,子盒子为已播放的蓝色进度条;
  • 类名为circle的span盒子为进度条白色拖拽点cTime为已播放时间,dTime为总时间,采用固定定位。

这是我初学Vue时写的,有很多不足,比如这里其实可以改进为flex弹性布局,大家可以在此基础上改进。

<audio ref="player" autoplay ></audio> 

//进度条 
<div class="bar">     
    <div class="progress-bar" @click="playMusic" ref="runfatbar">
        <div class="blue-bar" ref="runbar">
            <span class="circle"></span>     
        </div>     
    </div> 
</div> 

//时间 
<div class="time">{{cTime}}</div> 
<div class="all-time time">{{dTime}}</div>

css样式部分

  • 样式部分采用scss(原使用stylus,但本文面向初学者,改为scss更接近css更易理解)。
  • rem,相对长度单位,相对于根元素的字体大小的单位,常用于响应式布局;使用rem之前需全局设置字体大小,在此我设置的是html {font-size: 50px;},即1rem=50px。
进度条部分
<style scoped lang="scss">
.bar {
    width80%;   
    height: .3rem;   
    position: fixed;   
    bottom2.5rem;
    margin-left10%;
    .progress-bar {
        width100%;     
        height: .1rem;     
        margin-top: .1rem;     
        border-radius: .2rem;
        background-color#999999;
        .blue-bar {      
            height: .1rem;
            position: absolute;       
            top: .1rem;       
            left0;
            border-radius: .2rem; 
            background-color#1296db;
            .circle {
                width: .2rem;         
                height: .2rem;  
                position: absolute;         
                top: -.05rem;         
                right: -0.01rem;         
                border-radius10px;
                background-color#fff;
            }
        }
    }     
}      
</style>
歌曲时间部分
.time {    
    position: fixed;   
    bottom2.5rem;   
    font-size13px;   
    line-height: .5rem; 
}
.all-time {   
    right0;   
}

JS逻辑部分

歌曲播放进度条前进

进度条已经制作完毕,接下来就是获取已播放的时间与歌曲总时长,统一为00:00格式,还有渲染已播放的进度条,这里我是通过(已播放时长/总时长) * 进度条总长度来获取已播放的进度条长度。

data () {     
    return {       
        cTime'00:00'// 已播放时间       
        dTime'00:00',//总播放时间     
    }   
},    
//歌曲结束时重播
music.addEventListener('ended'() => {     
    music.play() 
})      
mounted () {     
    const music = this.$refs.player  // 音频所在对象
    const musicBar = this.$refs.runbar  // 颜色进度条所在对象
    const musicWidth = this.$refs.runfatbar.offsetWidth // 底部进度条总宽
    // 获得音频加载完成可播放时的处理     
    music.addEventListener('canplay'() => {
        const musicTime = music.duration // 获得音频时长 
        const branch = Math.floor(musicTime / 60// 计算音频分钟
        const second = Math.floor(musicTime % 60// 计算音频秒
        if (branch < 10 && second < 10) { // 四种情况判断音频总时间
            this.dTime = `0${branch}:0${second}`       
        } else if (branch < 10) {         
            this.dTime = `0${branch}:${second}`       
        } else if (second < 10) {         
            this.dTime = `${branch}:0${second}`       
        } else {         
            this.dTime = `${branch}:${second}`       
        }            
    }) 
    // 获得音频正在播放时的处理     
    music.addEventListener('timeupdate'() => {
        const musicTime = music.duration // 获得音频时长
        const stopTime = music.currentTime // 获得已播放的音频时长
        musicBar.style.width = `${(stopTime / musicTime) * 100}%` 
        // 计算进度条所在比例宽度
        const branch = Math.floor(stopTime / 60// 计算已播放的音频分钟
        const second = Math.floor(stopTime % 60// 计算已播放的音频秒
        if (branch < 10 && second < 10) { // 四种情况判断显示音频已播放时间
            this.cTime = `0${branch}:0${second}`       
        } else if (branch < 10) {
            this.cTime = `0${branch}:${second}`       
        } else if (second < 10) {         
            this.cTime = `${branch}:0${second}`       
        } else {         
            this.cTime = `${branch}:${second}`       
        }     
    }) 
}

到此为止,播放歌曲的同时,进度条也会前进,且各部播放完后会重播进度条也会重头开始。

点击、拖动进度条播放歌曲

基本的进度条与歌曲播放同步实现后,接下来,实现点击、拖动进度条来改变歌曲播放时间点。

mounted () {     
    const music = this.$refs.player  // 音频所在对象     const musicBar = this.$refs.runbar  // 颜色进度条所在对象     const musicWidth = this.$refs.runfatbar.offsetWidth // 底部进度条总宽      
    // 监听颜色进度条是否触摸拖动     musicBar.addEventListener('touchmove', (event) => {
        const events = event.targetTouches[0].pageX // 获得触摸拖动的距离
        if(events <= musicWidth) {
            musicBar.style.width = `${(events / musicWidth) * 100}%` // 计算进度条所在比例宽度                  
            //改变播放状态         
            music.pause() // 触摸拖动时停止播放         
            //改变播放状态图标         
            this.$refs.icon.innerHTML = ("&#xe634");       
          }     
    }) 
    // 监听颜色进度条是否触摸拖动结束     
    musicBar.addEventListener('touchend'() => {
        const touwidth = (musicBar.offsetWidth / musicWidth) // 计算进度条所在比例
        music.currentTime = music.duration * touwidth // 通过所在比例赋值给音频应在的播放时                  
        // 改变播放状态,进行播放         
        music.play()         
        this.$refs.icon.innerHTML = ("&#xe6ad");       
        if(touwidth < musicWidth) {         
            music.play() // 根据播放时间开始播放         
            // 更改播放暂停按钮为播放         
            this.$refs.icon.innerHTML = ("&#xe6ad");       
        }else if(touwidth >= musicWidth) {         
            music.pause() // 触摸拖动时停止播放         
            this.$refs.icon.innerHTML = ("&#xe634");       
        }     
    })   
},

图标来自阿里巴巴矢量图标库

最后

码云故障图.png 本来想加上git项目地址求star来着,但是发现最近码云硬件故障导致该项目看不了,唉,无奈。 最后,给孩子个赞安慰一下吧,蟹蟹!

蟹蟹.webp