需求:正在做的项目是一个SPA音乐播放器,用到了H5新加入的audio标签,同时像主流播放器一样显示当前播放歌曲的秒数和总时间;


思路:查阅API文档得知需要用到audio.currentTime和audio.duration分别表示当前播放时间和音频总时间,但如何用数据驱动的思想来使用成了第一个问题。

左思右想好像避免不了DOM操作,于是先用了dom.querySelector选中audio音频元素,再调用上面说到的2个方法来显示播放时间。


但实际操作起来并无效果,浏览器报错提示不能操作undefined对象的currentTime和duration方法;

怀疑是dom操作语句有问题,遂考虑使用ref引用来操作audio:

<audio ref='player' src='...' preload></audio>

<p>{{ cTime }}</p>

<p>{{ dTime }}</p>


data(){

    return{

cTime: null,

dTime: null

    }

},

mounted(){

    this.cTime = this.$refs.player.currentTime,

    this.dTime = this.$refs.player.duration

}


如此下来倒是不报错了,但是不管audio播放到什么时候,currentTime一直是0;而音频总时间则很诡异的为NaN。

经过一番查找,第一个问题是因为挂载mounted钩子只执行了一次当前时间也就是初始时间0,并没有进行监听,所以无法一直更新;

而第二个问题是浏览器的bug,某些主流浏览器需要监听canplay属性才能得到duration。


于是增加两个监听method:

methods: {
      addEventListeners: function () {
        const self = this;
        self.$refs.player.addEventListener('timeupdate', self._currentTime),
        self.$refs.player.addEventListener('canplay', self._durationTime)
      },
      removeEventListeners: function () {
        const self = this;
        self.$refs.player.removeEventListener('timeupdate', self._currentTime)
        self.$refs.player.removeEventListener('canplay', self._durationTime)
      },
      _currentTime: function () {
        const self = this;
        self.timeNow = parseInt(self.$refs.player.currentTime)
      },
      _durationTime: function () {
        const self = this;
        self.timeDuration = parseInt(self.$refs.player.duration)
      }
    },
    mounted() {
      this.addEventListeners()
    },
    beforeDestroyed() {
      this.removeEventListeners()
    }


如此,便能正确监听到动态当前时间和音频总时间了。

后期只要对获取到的时间做个小处理,变成时:分:秒的形式就可以,代码很简单就不贴出来了。


至此,这个audio的坑基本解决,值得一提的是中间还尝试了Vue.nextTick方法,但在这个demo中却并不适用,

其原理是等dom更新后执行返回函数,但我们这个audio在播放中currentTime的改变并不会引发dom的更新,

所以同样不能监听到。

Logo

前往低代码交流专区