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

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

背景介绍

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

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

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

设计实现

思路:

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

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

具体实现:

以下代码基于VUE框架

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

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

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

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

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

html代码

ini 复制代码
<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代码

xml 复制代码
<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、播放暂停控制

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

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

@play="handleTimeProgress"

kotlin 复制代码
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"

javascript 复制代码
handlePause() {
    this.playStatus = false;
    clearInterval(this.timer);
},

6、显示音频总时长

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

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

kotlin 复制代码
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"

ini 复制代码
//鼠标按下事件触发
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();
},

总结

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

相关推荐
CodeClimb2 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
光头程序员4 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
fmdpenny5 小时前
Vue3初学之商品的增,删,改功能
开发语言·javascript·vue.js
小美的打工日记5 小时前
ES6+新特性,var、let 和 const 的区别
前端·javascript·es6
涔溪5 小时前
有哪些常见的 Vue 错误?
前端·javascript·vue.js
程序猿online5 小时前
前端jquery 实现文本框输入出现自动补全提示功能
前端·javascript·jquery
Turtle7 小时前
SPA路由的实现原理
前端·javascript
HsuYang8 小时前
Vite源码学习(九)——DEV流程中的核心类(下)
前端·javascript·架构
傻小胖8 小时前
React 中hooks之useInsertionEffect用法总结
前端·javascript·react.js
蓝冰凌10 小时前
【整理】js逆向工程
javascript·js逆向