封装audio,自定义样式,倍速,进度条,音量控制,无脑直接使用

<template>
  <div class="container">
    <audio
      ref="audio"
      controls
      :src="src"
      style="display: none"
      @canplay="bofang"
      @timeupdate="timeupdate"
    ></audio>
    <div class="myAudio">
      <img
        v-if="playing"
        class="imgLB"
        style="width: 16px"
        src="https://img0.baidu.com/it/u=933426644,47345326&fm=253&fmt=auto&app=138&f=JPEG"
        alt=""
        @click="onPause()"
      />
      <img
        v-else
        class="imgLB"
        style="width: 16px"
        src="https://img1.baidu.com/it/u=1308789919,755843987&fm=253&fmt=auto&app=138&f=JPEG"
        alt=""
        @click="onPlay()"
      />

      <div class="progress">
        <el-slider
          v-model="value"
          :show-tooltip="false"
          @change="change"
          @mousedown.native="isChange = true"
          @mouseup.native="isChange = false"
        ></el-slider>
      </div>
      <div class="nowTime">{
   
   { nowTime }}</div>
      <div>|</div>
      <div class="allTime">{
   
   { allTime }}</div>
      <div v-click-outside="handleClickOutvolumeView" class="volumeView">
        <img
          class="imgLB"
          style="width: 14px"
          src="https://bpic.51yuansu.com/pic3/cover/01/22/90/59224a03eabfa_610.jpg"
          alt=""
          @click="openVolume"
        />
        <div v-show="showVolume" class="volumeSlider">
          <div class="volumeValue">{
   
   { volumeValue }}</div>
          <el-slider
            v-model="volumeValue"
            :show-tooltip="false"
            vertical
            height="100px"
            @change="changeVol"
          >
          </el-slider>
        </div>
      </div>
      <div v-click-outside="handleClickOutsideSpeed" class="openSpeed" @click="toOpenSpeed">
        <div class="speedText">倍速&nbsp;{
   
   { speed }}</div>
        <div v-show="openSpeed" class="speedSelect">
          <div
            v-for="(item, index) in speedOptions"
            :key="index"
            class="itemspeed"
            @click.stop="selectSpeed(item)"
          >
            {
   
   { item.label }}
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
/*
音频播放组件指引:
1.引用组件
2.通过props传入src音频地址,例:<myAudio ref="audio" :src="http://.....mp3" />
3.若需关闭音频,可通过ref调用onPause()方法,例:this.$refs.audio.onPause();
4.若需关闭音频后将进度条重置,可通过ref调用resetTime()方法
*/
export default {
  directives: {
    'click-outside': {
      bind(el, binding, vnode) {
        console.log('bind');
        function eventHandler(e) {
          if (el.contains(e.target)) {
            return false;
          }
          // 如果绑定的参数是函数,正常情况也应该是函数,执行
          if (binding.value && typeof binding.value === 'function') {
            binding.value(e);
          }
        }
        // 用于销毁前注销事件监听
        el.__click_outside__ = eventHandler;
        // 添加事件监听
        document.addEventListener('click', eventHandler);
      },

      unbind(el, binding, vnode) {
        console.log('unbind');

        // 移除事件监听
        document.removeEventListener('click', el.__click_outside__);
        // 删除无用属性
        delete el.__click_outside__;
      },
    },
  },
  props: {
    src: {
      default: 'http://music.163.com/song/media/outer/url?id=1337065812.mp3',
      type: String,
    },
  },
  data() {
    return {
      playing: false,
      value: 0,//播放时间进度条
      volumeValue: 0, //音量
      showVolume: false, //显示音量
      max: 0,
      allTime: '00:00',
      nowTime: '00:00',
      speed: '1.0×',
      openSpeed: false,
      //判断是否被拖动
      isChange: false,
      speedOptions: [
        {
          value: 0.5,
          label: '0.5×',
        },
        {
          value: 0.75,
          label: '0.7×',
        },
        {
          value: 1,
          label: '1.0×',
        },
        {
          value: 1.5,
          label: '1.5×',
        },
        {
          value: 2,
          label: '2.0×',
        },
        {
          value: 3,
          label: '3.0×',
        },
      ],
    };
  },
  created() {},
  mounted() {},
  methods: {
    change() {
      if (this.max === 0) return;
      this.$refs.audio.currentTime = (this.value / 100) * this.max;
      this.isChange = false;
    },
    bofang() {
      this.max = this.$refs.audio.duration;
      this.allTime = this.timeFormat(this.max);
      this.volumeValue = this.$refs.audio.volume * 100;
      console.log(this.$refs.audio.duration);
    },
    timeupdate() {
      if (this.isChange === true) return;
      this.value = (this.$refs.audio.currentTime / this.max) * 100;
      this.nowTime = this.timeFormat(this.$refs.audio.currentTime);
    },
    // 音频播放
    onPlay() {
      this.playing = true;
      console.log('音频播放');
      this.$refs.audio.play();
    },
    // 当音频暂停
    onPause() {
      this.playing = false;
      console.log('音频暂停');
      this.$refs.audio.pause();
    },
    //将单位为秒的的时间转换成mm:ss的形式
    timeFormat(number) {
      var minute = parseInt(number / 60);
      var second = parseInt(number % 60);
      minute = minute >= 10 ? minute : '0' + minute;
      second = second >= 10 ? second : '0' + second;
      return minute + ':' + second;
    },
    toOpenSpeed() {
      this.openSpeed = true;
    },
    selectSpeed(item) {
      this.$refs.audio.playbackRate = item.value;
      this.openSpeed = false;
      this.speed = item.label;
    },
    openVolume() {
      this.showVolume = true;
    },
    //改变音量
    changeVol(val) {
      this.$refs.audio.volume = val / 100;
      this.showVolume = false;
    },
    handleClickOutvolumeView() {
      this.showVolume = false;
    },
    handleClickOutsideSpeed() {
      this.openSpeed = false;
    },
    //将进度条归零
    resetTime() {
      this.$refs.audio.currentTime = 0;
    },
  },
};
</script>
<style lang="scss" scoped>
.container {
  font-size: 12px;
}
.myAudio {
  width: 320px;
  height: 46px;
  border: 1px solid #d9d9d9;
  display: flex;
  align-items: center;
  padding: 0 10px;
  background-color: #fffffe;
  border-radius: 3px;
  color: #8c8c8c;
  .progress {
    width: 120px;
    margin: 0 10px 0 10px;
    ::v-deep .sp-slider__button-wrapper {
      width: 20px;
      height: 20px;
      margin-top: 8px;
    }
    ::v-deep .sp-slider__button {
      width: 12px;
      height: 12px;
      background-color: #4974f5;
    }
  }
  .nowTime {
    margin-right: 3px;
    white-space: nowrap;
  }
  .allTime {
    margin: 0 5px 0 3px;
    white-space: nowrap;
  }
  .volumeView {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-right: 3px;
    .imgLB {
      width: 20px;
    }
    .volumeSlider {
      position: absolute;
      bottom: 22px;
      left: -8px;
      background: #fff;
      border-radius: 5px;
      box-shadow: 0 0 10px #8c8c8c;
      padding: 0px 0 10px 0;
      .volumeValue {
        margin: 10px 0;
        text-align: center;
      }
    }
  }

  .openSpeed {
    position: relative;
    .speedText {
      white-space: nowrap;
    }
    .speedSelect {
      position: absolute;
      background: #fff;
      padding-left: 5px;
      bottom: 28px;
      box-shadow: 0 0 10px #8c8c8c;
      border-radius: 3px;
      .itemspeed {
        width: 40px;
        line-height: 18px;
      }
      .itemspeed:hover {
        background-color: #ecf1fd;
      }
    }
  }
}
</style>

猜你喜欢

转载自blog.csdn.net/Xwf1023/article/details/129403751