vue h5项目自定义audio组件,进度条可拖拽

在这里插入图片描述
思路:先按照原生audio组件,将如何控制播放暂停写出来,通过相关属性获得当前播放时间以及总时长,然后难点在于如何实现进度条的拖拽,控制时间的显示。

相关拖拽:

 // touchstart	触摸开始,多点触控,后面的手指同样会触发
    // touchmove	接触点改变,滑动时
    // touchend	触摸结束,手指离开屏幕时
    // touchcancel	触摸被取消,当系统停止跟踪触摸的时候触发

全部代码



<template>
  <div>
    <!-- 此处的ref属性,可以很方便的在vue组件中通过 this.$refs.audio获取该dom元素 -->
    <audio
      ref="audio"
      @pause="onPause"
      @play="onPlay"
      @timeupdate="handleAudioTimeUpdated"
      @loadedmetadata="onLoadedmetadata"
      src="https://cdn.hyxhbao.com/front/static/h5_hyxhb_img/audio/audio.mp3"
      controls="controls"
      style="display: none"
    ></audio>
    <!-- 音频播放控件 -->
    <div class="p_cotrol">
      <div @click="playaudio">
        <div v-if="audio.playing">
          <img
            class="p_img"
            @click="onPlay()"
            src="https://cdn.hyxhbao.com/front/static/h5_hyxhb_img/audio/pause.png"
            alt=""
          />
        </div>

        <div v-else>
          <img
            class="p_img"
            @click="onPause()"
            src="https://cdn.hyxhbao.com/front/static/h5_hyxhb_img/audio/play.png"
            alt=""
          />
        </div>
      </div>
      <div class="p_time">{
   
   { audio.currentTime | formatSecond }}</div>
      <div class="p_slider" @touchstart="handleTouchStart">
        <div class="p_slider_track"></div>
        <div class="p_slider_fill" :style="'width:' + sliderTime + '%'"></div>
        <div class="p_slider_thumb" :style="'left:' + sliderTime + '%'"></div>
      </div>

      <div class="p_time">{
   
   { audio.maxTime | formatSecond }}</div>
    </div>
  </div>
</template>

<script>
// 将整数转换成 时:分:秒的格式
function realFormatSecond(second) {
  var secondType = typeof second;

  if (secondType === "number" || secondType === "string") {
    second = parseInt(second);

    var hours = Math.floor(second / 3600);
    second = second - hours * 3600;
    var mimute = Math.floor(second / 60);
    second = second - mimute * 60;

    return (
      hours + ":" + ("0" + mimute).slice(-2) + ":" + ("0" + second).slice(-2)
    );
  } else {
    return "0:00:00";
  }
}
export default {
  name: "demo",

  data() {
    return {
      sliderTime: 0, //滑动进度时间
      audio: {
        playing: false, // 该字段是音频是否处于播放状态的属性
        currentTime: 0, // 音频当前播放时长
        maxTime: 0, // 音频最大播放时长
        minTime: 0,
        step: 0.1,
      },
    };
  },
  watch: {},
  mounted() {
    let audio = document.getElementById("audioPlay");
  },
  methods: {
    // 控制音频的播放与暂停
    playaudio() {
      console.log("控制音频的播放与暂停");
      return this.audio.playing ? this.pause() : this.play();
    },
    // 播放音频
    play() {
      this.$refs.audio.play();
    },
    // 暂停音频
    pause() {
      this.$refs.audio.pause();
      console.log("暂停音频");
    },
    // 音频播放
    onPlay() {
      this.audio.playing = true;
      console.log("音频播放");
    },
    // 当音频暂停
    onPause() {
      this.audio.playing = false;
    },
    // 当指定的音频/视频的元数据已加载时,会发生 loadedmetadata 事件。
    onLoadedmetadata(res) {
      console.log("loadedmetadata数据已加载时");
      this.audio.maxTime = parseInt(res.target.duration);
    },
    // 当音频当前时间改变后,进度条也要改变
    handleAudioTimeUpdated(res) {
      console.log("timeupdate");
      // console.log(res.target.currentTime)
      this.audio.currentTime = res.target.currentTime;
      this.sliderTime = parseInt(
        (this.audio.currentTime / this.audio.maxTime) * 100
      );
    },

    // 进度条格式化toolTip
    formatProcessToolTip(index = 0) {
      index = parseInt((this.audio.maxTime / 100) * index);
      return "进度条: " + realFormatSecond(index);
    },
    // touchstart	触摸开始,多点触控,后面的手指同样会触发
    // touchmove	接触点改变,滑动时
    // touchend	触摸结束,手指离开屏幕时
    // touchcancel	触摸被取消,当系统停止跟踪触摸的时候触发
    handleTouchStart(e) {
       console.log(e);
      this.setValue(e.touches[0]);
      document.addEventListener("touchmove", this.handleTouchMove);
      document.addEventListener("touchup", this.handleTouchEnd);
      document.addEventListener("touchend", this.handleTouchEnd);
      document.addEventListener("touchcancel", this.handleTouchEnd);
    },
    handleTouchMove(e) {
      console.log(e.changedTouches[0]);
      this.setValue(e.changedTouches[0]);
    },
    handleTouchEnd(e) {
      this.setValue(e.changedTouches[0]);
      document.removeEventListener("touchmove", this.handleTouchMove);
      document.removeEventListener("touchup", this.handleTouchEnd);
      document.removeEventListener("touchend", this.handleTouchEnd);
      document.removeEventListener("touchcancel", this.handleTouchEnd);
    },
    // 从点击位置更新 value
    setValue(e) {
      // Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。
      //clientX  点击位置距离当前body可视区域的x,y坐标
      // console.log(e, this.audio, this.$e);
      const $el = this.$el;
      const { maxTime, minTime, step } = this.audio;
      // console.log($el,'$el.offsetWidth')
      let value =
        ((e.clientX - $el.getBoundingClientRect().left) / $el.offsetWidth) *
        (maxTime - minTime);
      value = Math.round(value / step) * step + minTime;
      value = parseFloat(value.toFixed(5));
      if (value > maxTime) {
        value = maxTime;
      } else if (value < minTime) {
        value = minTime;
      }
      this.$refs.audio.currentTime = value;
    },
    // 拖动进度条,改变当前时间,index是进度条改变时的回调函数的参数0-100之间,需要换算成实际时间
    changeCurrentTime(index) {
      console.log("拖动进度条");
      // console.log('拖动了',index,this.sliderTime,this.audio.maxTime,parseInt(index / 100 * this.audio.maxTime))
      this.$refs.audio.currentTime = parseInt(
        (index / 100) * this.audio.maxTime
      );
    },
  },
  filters: {
    // 将整数转化成时分秒
    formatSecond(second = 0) {
      return realFormatSecond(second);
    },
  },
};
</script>

<style scoped lang="scss">
.p_cotrol {
  margin: 0 auto;
  display: flex;
  width: 90%;
  padding: 20px;
  background-color: #fff;
  .p_img {
    width: 30px;
    height: 30px;
  }
  .p_time {
    font-size: 14px;
    line-height: 30px;
    margin: 0 10px;
  }

  // 进度条
  .p_slider {
    width: 100%;
    position: relative;
    height: 24px;
    display: flex;
    align-items: center;
    cursor: default;
    user-select: none;
    outline: none;
  }

  .p_slider_track {
    position: absolute;
    height: 2px;
    left: 0;
    right: 0;
    top: 50%;
    margin-top: -1px;
    background-color: #f7e4a5;
  }

  .p_slider_fill {
    position: absolute;
    height: 2px;
    width: 100%;
    background-color: #ffcd3a;
    left: 0;
    top: 50%;
    margin-top: -1px;
  }

  .p_slider_thumb {
    position: absolute;
    top: 50%;
    width: 12px;
    height: 12px;
    background-color: #ffcd3a;
    color: #ffcd3a;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    cursor: pointer;
  }
}
</style>

Guess you like

Origin blog.csdn.net/qq_43671996/article/details/110958816