携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情
歌曲播放进度条效果图
首先先上效果图吧,基于Vue2实现了一个基础的音乐播放进度条,左侧为歌曲已播放时长,右侧为歌曲总时长,进度条蓝色部分为已播放部分。
实现
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 {
width: 80%;
height: .3rem;
position: fixed;
bottom: 2.5rem;
margin-left: 10%;
.progress-bar {
width: 100%;
height: .1rem;
margin-top: .1rem;
border-radius: .2rem;
background-color: #999999;
.blue-bar {
height: .1rem;
position: absolute;
top: .1rem;
left: 0;
border-radius: .2rem;
background-color: #1296db;
.circle {
width: .2rem;
height: .2rem;
position: absolute;
top: -.05rem;
right: -0.01rem;
border-radius: 10px;
background-color: #fff;
}
}
}
}
</style>
歌曲时间部分
.time {
position: fixed;
bottom: 2.5rem;
font-size: 13px;
line-height: .5rem;
}
.all-time {
right: 0;
}
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 = ("");
}
})
// 监听颜色进度条是否触摸拖动结束
musicBar.addEventListener('touchend', () => {
const touwidth = (musicBar.offsetWidth / musicWidth) // 计算进度条所在比例
music.currentTime = music.duration * touwidth // 通过所在比例赋值给音频应在的播放时
// 改变播放状态,进行播放
music.play()
this.$refs.icon.innerHTML = ("");
if(touwidth < musicWidth) {
music.play() // 根据播放时间开始播放
// 更改播放暂停按钮为播放
this.$refs.icon.innerHTML = ("");
}else if(touwidth >= musicWidth) {
music.pause() // 触摸拖动时停止播放
this.$refs.icon.innerHTML = ("");
}
})
},
图标来自阿里巴巴矢量图标库。
最后
本来想加上git项目地址求star来着,但是发现最近码云硬件故障导致该项目看不了,唉,无奈。
最后,给孩子个赞安慰一下吧,蟹蟹!