vue实现audio进度拖拽播放及拖拽播放问题解决

    技术2025-07-10  6

    vue+elementUi简单实现audio拖拽播放

    前言: 很久之前做过的一个录音播放功能,当时播放拖拽进度的时候出现了进度条拖到目标位置松手后又退回去的bug,现在想起来把实现过程和解决方法简单再写一遍,希望能给需要帮助的同学提供一份参考。

    本次小demo使用了elementUi中的slider,font-awesome中的播放图标,vue中安装及使用方法如下:

    npm i element-ui font-awesome -S 然后在main.js中使用

    引入elementUi: import ElementUI from ‘element-ui’; import ‘element-ui/lib/theme-chalk/index.css’; Vue.use(ElementUI);引入font-awesome: import ‘font-awesome/css/font-awesome.css’;

    使用原audio标签加载音频,不显示原音频控件,通过DIY控件控制audio标签API即可。

    DIY控件部分代码 <audio ref="audio" @play="playFunc" @pause="pauseFunc" @timeupdate="timeupdateFunc" @canplay="canplayFunc" @error="errorFunc"> <source src="../summerWind.mp3" type="audio/mpeg"> </audio> <div class="audioControl"> <div class="errorMask" v-show="isError">{{errorMsg}}</div> <p>{{musicName}}</p> <div style="display:flex;align-items: center;"> <el-slider v-model="playProcess" class="sliderClass" style="width: 95%;" @change="setProcessFunc" :format-tooltip="formatTooltip"></el-slider> <div style="color:white;width: 120px;text-align: right;">{{formatCurrentTime}} / {{formatDuration}}</div> </div> <div class="playControl"> <span class="audioSpan" @click="clickFunc('backward')"><i class="fa fa-backward" aria-hidden="true"></i></span> <span class="audioSpan" @click="clickFunc('play')" v-show="!isPlaying"><i class="fa fa-play-circle-o audioIcon" aria-hidden="true"></i></span> <span class="audioSpan" @click="clickFunc('pause')" v-show="isPlaying"><i class="fa fa fa-pause-circle-o audioIcon" aria-hidden="true"></i></span> <span class="audioSpan" @click="clickFunc('forward')"><i class="fa fa-forward " aria-hidden="true"></i></span> <span class="audioSpan" @click="clickFunc('refresh')"><i class="fa fa-refresh" aria-hidden="true"></i></span> <span class="audioSpan" style="width:50px;"> <span class="speed">X {{playSpeed | fmtPlaySpeed()}}</span> </span> <span class="audioVolSpan"><i class="fa fa-volume-up volume" aria-hidden="true"></i></span> <el-slider v-model="playVolume" class="sliderVolumClass" :format-tooltip="formatTooltipVol" @change="setVolumeFunc"></el-slider> </div> </div> 播放部分js代码 methods:{ formatTooltip(val){ let currTime = Math.floor(val/100*this.totalTimes); let tempMin = Math.floor(currTime / 60); let tempSec = currTime % 60; let min,sec; return `${toStringFunc(tempMin)}:${toStringFunc(tempSec)}`; }, formatTooltipVol(vol){ return Math.round(vol*2/100*10)/10; }, clickFunc(val){ if(val == 'play'){ this.isPlaying = !this.isPlaying; this.$refs.audio.play(); }else if(val == 'pause'){ this.isPlaying = !this.isPlaying; this.$refs.audio.pause(); }else if(val == 'backward'){ //减慢音频播放速度,速率范围[0.5,2] if(this.playSpeed > 0.5){ this.playSpeed -= 0.5; this.$refs.audio.playbackRate = this.playSpeed; } }else if(val == 'forward'){ //加快音频播放速度,速率范围[0.5,2] if(this.playSpeed < 2){ this.playSpeed += 0.5; this.$refs.audio.playbackRate = this.playSpeed; } }else if(val == 'refresh'){ this.$refs.audio.playbackRate = 1; this.playSpeed = 1; this.$refs.audio.load(); this.$refs.audio.play(); } },

    功能实现了,但在播放音乐时,拖动进度条出现如下问题:

    经初步分析,出现这种问题的原因是audio的timeupdate方法约每秒触发一次,js代码在播放音频时没有进行处理,此方法一直在修改slider的model值,当把滑块拖到目标位置(过程超过1s)松开时,slider拖动的实际值已经被timeupdate修改成了currentTime,所以松手后滑块会立刻回到currentTime值的位置。


    拖动slider触发的方法

    setProcessFunc(val){ this.$refs.audio.currentTime = Math.round(val/100*this.totalTimes); this.$refs.audio.play(); }

    audio的timeupdate方法

    timeupdateFunc(e){ this.playProcess = (e.target.currentTime)/this.totalTimes*100; this.currentTime = e.target.currentTime; }

    既然问题的原因找到了,那么解决这个问题也很简单:只要在拖动滑块不松开的过程中timeupdate方法不修改slider的model值就行了,即增加一个flag,给滑块加上鼠标事件mousedown、mouseup,鼠标按下(意味着在拖动)flag为true,鼠标松开(拖动结束)flag为false,timeupdate事件只在flag为false时才对slider的model值进行修改就行了。

    修改后的代码如下


    最后大功告成!最终效果如下:

    Processed: 0.012, SQL: 9