vue 自定义音频

946 阅读1分钟

问题:

由于audio标签原生样式不能满足项目需要,需要自定义样式,项目使用技术为vue3和ant-design,将自定义audio封装为一个组件,可以在其他组件内进行引用,主要进行了以下修改:

  1. 隐藏原生audio标签
  2. 通过div实现自定义样式
  3. 控制div操作audio 对象的属性和方法

原生样式:

image.png

修改后样式:

截屏2022-08-11 下午4.41.53.png

组件封装

<template>
  <div>
    <audio @timeupdate="updateProgress" controls ref="audioRef" style="display: none">
      <source :src="fileurl" />
      您的浏览器不支持音频播放
    </audio>
    <div class="audio-right">
      <div class="play-stop-icon" @click="playAudio">
        <CaretRightOutlined
          v-if="audioStatus !== 'pause'"
          class="dialogAudioPlay"
        ></CaretRightOutlined>
        <PauseOutlined v-else class="dialogAudioPlay"></PauseOutlined>
      </div>

      <div class="progress-bar-bg" id="progressBarBg">
        <Slider :tip-formatter="formatter" v-model:value="playTime" @change="sliderChange" />
      </div>
      <div class="audio-time" style="min-height: 10px">
        <span class="audio-length-current" id="audioCurTime">{{ audioStart }}</span
        >/
        <span class="audio-length-total">{{ duration }}</span>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
  import {
    defineComponent,
    ref,
    reactive,
    watchEffect,
    inject,
    onMounted,
    nextTick,
    watch,
    computed,
    toRef,
    toRefs,
  } from 'vue';
  import { CaretRightOutlined, PauseOutlined } from '@ant-design/icons-vue';
  import { propTypes } from '/@/utils/propTypes';
  import { Slider } from 'ant-design-vue';
  import { transTime } from '/@/utils/time';
  export default defineComponent({
    components: {
      CaretRightOutlined,
      PauseOutlined,
      Slider,
      // [Slider.name]: Slider,
    },
    props: {
      fileurl: propTypes.string,
    },
    setup(props, context) {
      let audioStatus = ref('play');
      let audioStart = ref<number | string>('0:00');
      let audioVolume = ref(0.5);
      let audioHuds = ref(false);
      let audioRef = ref<HTMLAudioElement | null>(null);
      let duration = ref<number | string>();
      let durationSecond = ref<number>();
      let playPercentage = ref<number>();
      let playTime = ref<number | string>('0:00');

      function fetch() {
        let myVid = audioRef.value;
        if (!myVid) return;
        myVid.loop = false;
        // 监听音频播放完毕
        myVid.addEventListener(
          'ended',
          function () {
            audioStatus.value = 'play'; // 显示播放icon
          },
          false,
        );
        if (myVid != null) {
          myVid.oncanplay = function () {
            durationSecond.value = myVid?.duration;
            duration.value = transTime(myVid?.duration); // 计算音频时长
          };
          myVid.volume = 0.5; // 设置音量50%
        }
      }

      // 播放暂停控制
      function playAudio() {
        let recordAudio = audioRef.value; // 获取audio元素
        if (recordAudio?.paused) {
          recordAudio?.play();
          audioStatus.value = 'pause';
        } else {
          recordAudio?.pause();
          audioStatus.value = 'play';
        }
      }
      const formatter = (value: number) => {
        playTime.value = value;
        return audioStart.value;
      };
      // 更新进度条与当前播放时间
      function updateProgress(e) {
        playPercentage.value = e.target.currentTime / e.target.duration;
        audioStart.value = transTime(e.target.currentTime);
        playTime.value = Math.round(Number(playPercentage.value * 100));
        if (e.target.currentTime === e.target.duration) {
          audioStatus.value = 'pause';
        }
      }
      function sliderChange() {
        if (durationSecond.value) {
          //拖拽时改变时长
          //value 拖拽条的值, durationSecond.value 音频时长的秒数
          //value = 当前时间/总时间*100 即 当前时间 = value*总时间/100
          audioRef.value!.currentTime = (Number(playTime.value) * durationSecond.value) / 100;
        }
      }
      computed(() => {});
      onMounted(() => {
        fetch();
      });

      return {
        audioStatus,
        audioStart,
        duration,
        audioVolume,
        audioHuds,
        audioRef,
        fetch,
        playAudio,
        updateProgress,
        playTime,
        formatter,
        playPercentage,
        durationSecond,
        sliderChange,
      };
    },
  });
</script>
<style lang="less" scoped>
  .audio-right {
    width: 100%;
    height: 38px;
    line-height: 38px;
    background: rgba(0, 0, 0, 0.04);
    border-radius: 19px;
    display: flex;
    padding: 0 8px 0 6px;
    .play-stop-icon {
      background-color: #fff;
      height: 30px;
      width: 30px;
      border-radius: 30px;
      margin-top: 4px;
      position: relative;
      .dialogAudioPlay {
        cursor: pointer;
        color: #5c5e66;
        font-size: 20px;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
      }
    }
    .progress-bar-bg {
      flex: 1;
      padding-top: 3px;
      cursor: pointer;
      margin: 0 10px;
    }
    :global(.ant-slider) {
      // height: 100%;
      box-sizing: border-box;
    }
    :global(.ant-slider-rail) {
      background-color: #d9d9d9 !important;
    }
    .progress-bar {
      background-color: #56bf8b;
      width: 0%;
      height: 10px;
      border-radius: 5px;
    }

    .audio-time {
      overflow: hidden;
      font-size: 14px;
      .audio-length-total {
        float: right;
      }
      .audio-length-current {
        float: left;
      }
    }
  }
</style>

参考:vue自定义音频audio样式及操作面板https(博主使用的vue2,我根据博主代码改为了vue3,供参考)