likes
comments
collection
share

自定义H5音频播放组件样式

作者站长头像
站长
· 阅读数 10

自定义H5音频播放组件样式

背景介绍

简介:audio为html5中的新属性。定义声音,比如音乐或者其他的音频流。

背景:最近在做的警情指挥项目中需要完成一个播放警情录音的功能。组内的小伙伴觉得改原生的样式有些无从下手,所以分享一下具体思路和实现方式供大家参考。该思路和实现方式同样适用于自定义视频播放进度条、按钮等样式。

效果如下,小圆点可拖拽:

自定义H5音频播放组件样式

设计实现

思路:

H5 的 <audio> 标签是由浏览器负责实现默认样式的。所以不同的浏览器样式不一样,有些还不太美观。所以我们一般会去掉默认样式,自己重新写。具体操作是定义 <audio> 的时候去掉 controls 属性,这样就可以隐藏原生的 audio, 然后就可以加上自己写的 html + css 代码了。最后用 ref 方式捕获 audio 对象,为它添加各种播放控制事件。

首先大家可以看下手册,里面会介绍一些属性、方法、事件等,后面会用到 www.w3school.com.cn/tags/html_r…

具体实现:

以下代码基于VUE框架

1、已播放进度条样式长度控制

利用vue computed属性根据比例实时计算已播放dom的width

computed: {
  scaleProgress() {
   if (this.scale) {
•    return 'width:' + this.scale * 100 + '%';
   } else {
•    return 'width:0';
   }
  }
},

2、定义标签和进度条按钮等样式

样式根据视觉稿还原,这部分比较简单,只需关注下关键节点事件方法和变量属性,后续会用到,需要知道这些关键节点需执行的函数。

html代码

<template>
  <div class="audio-play">
    <audio
      ref="audio"
      preload
      @pause="handlePause"
      @play="handleTimeProgress"
      @canplay="computedFullTime"
      :src="audioUrl"
    ></audio>
    <div class="control-btn" @click="playStatusChange">
      <div :class="playStatus ? 'play' : 'stop'"></div>
    </div>
    <div class="control-line">
      <div ref="fullLine" class="bottom-line">
        <div class="played-line" :style="scaleProgress"></div>
        <div ref="point" class="play-point" @mousedown="handleMouseDown">
          <div class="point"></div>
        </div>
        <div class="played-time">{{ playTime }}</div>
      </div>
      <div class="al-time">{{ fullTime }}</div>
    </div>
  </div>
</template>

css代码

<style lang="less">
.audio-play {
  height: 18px;
  width: 286px;
  margin-left: 8px;
  display: flex;
  .control-btn {
    height: 18px;
    width: 18px;
    .play {
      height: 18px;
      width: 18px;
      background: url('~@/assets/images/alarmCommand/stop.png');
    }
    .stop {
      height: 18px;
      width: 18px;
      background: url('~@/assets/images/alarmCommand/play.png');
    }
  }
  .control-line {
    width: 260px;
    margin-left: 6px;
    .al-time {
      float: right;
      opacity: 0.6;
      font-family: PingFangSC-Semibold;
      font-size: 12px;
      color: #78aaff;
      margin-top: 4px;
    }
    .bottom-line {
      display: flex;
      position: relative;
      margin-top: 8px;
      height: 4px;
      width: 260px;
      background: rgba(5, 124, 255, 0.13);
      border-radius: 2px;
      .played-line {
        background-image: linear-gradient(90deg, #43b7fc 0%, #2080f7 93%);
        border-radius: 2px;
        height: 4px;
        // width: 20%;
      }
      .played-time {
        position: absolute;
        opacity: 0.6;
        font-family: PingFangSC-Semibold;
        font-size: 12px;
        color: #78aaff;
        left: -18px;
        top: 10px;
      }
      .play-point {
        position: relative;
        height: 10px;
        width: 10px;
        background: #ffffff;
        border: 1px solid #2080f7;
        border-radius: 5px;
        margin-left: -5px;
        margin-top: -3px;
        .point {
          background: #7fbcff;
          height: 4px;
          width: 4px;
          margin: 2px;
          border-radius: 2px;
        }
      }
    }
  }
}
</style>

3、播放暂停控制

//播放按钮点击切换事件
playStatusChange() {
    this.playStatus = !this.playStatus;
    if (this.playStatus) {
        this.$refs.audio.play();
    } else {
        this.$refs.audio.pause();
    }
}

4、为audio添加播放事件,更新进度条和当前播放时间

@play="handleTimeProgress"

handleTimeProgress() {
    this.timer = setInterval(this.playing, 1000);
},
playing() {
    // 正在播放中
    this.scale = this.$refs.audio.currentTime / this.$refs.audio.duration;
    this.playTime = this.formatTime(this.$refs.audio.currentTime);
},

5、给audio标签添加暂停事件,清除定时器

@pause="handlePause"

handlePause() {
    this.playStatus = false;
    clearInterval(this.timer);
},

6、显示音频总时长

@canplay="computedFullTime" ,根据duration属性获取音频总时长,单位为秒S

formatTime为封装好的一个函数,目的是将秒转换为几分几秒的格式

computedFullTime() {
   this.fullTime = this.formatTime(this.$refs.audio.duration);
},
formatTime(val) {
    val = Math.round(val);
    const min = Math.floor(val / 60);
    const sec = val % 60;
    return this.setZero(min) + ':' + this.setZero(sec);
},
setZero(val) {
    if (val < 10) {
        return '0' + val;
    } else {
        return '' + val;
    }
}

7、进度条拖拽控制

拖拽小圆点添加鼠标点击事件 @mousedown="handleMouseDown"

//鼠标按下事件触发
handleMouseDown(ev) {
    const that = this;
    const downX = ev.pageX;
    const downL = this.$refs.point.offsetLeft;
    //鼠标移动事件
    document.onmousemove = ev => {
        let scale =
            (ev.pageX - downX + downL + 8) / that.$refs.fullLine.offsetWidth;
        if (scale < 0) {
            scale = 0;
        } else if (scale > 1) {
            scale = 1;
        }
        that.scale = scale;
        that.$refs.audio.currentTime = scale * that.$refs.audio.duration;
        that.playTime = that.formatTime(that.$refs.audio.currentTime);
    };
    document.onmouseup = () => {
        document.onmousemove = document.onmouseup = null;
    };
    ev.preventDefault();
},

总结

本文介绍到此结束,其实还有好多别的控制,比如音量大小,快退快进等。原理明白后,一切都变得简单。有些时候就是这样,感觉是个庞然大物,其实了解之后并没有想象的复杂。