封装一个audio音频组件,包含前进后退及进度条等

27 篇文章 0 订阅

因为项目里有这个需求,所以我参考别人的代码,加上自己的理解,把audio组件封装了一下,当然这个是最基本的,具体的还得根据不同的项目需求来改造。

来看完整代码(在vue中封装的):

<template>
  <!-- 录音播放区域 -->
  <div>
    <div class="h4-meeting">Meeting</div>
    <audio
      @canplay="getDuration"
      controls
      @timeupdate="updateTime"
      v-show="false"
      ref="audio"
      :src="audioSrc"
    />
    <div class="card">
      <div
        class="progress"
        ref="progress"
        @click="clickProgress"
        @mouseup="handleMouseup"
      >
        <div class="currentProgress" ref="currentProgress">
          <span class="circle" ref="circle" @mousedown="handleMousedown"></span>
        </div>
      </div>
      <div class="time">
        <span class="startTime">{{ currentDuration }}</span>
        <span class="endTime">{{ duration }}</span>
      </div>
      <div class="option">
        <span class="pre" @click="handleBack">
          <svg-icon
            name="icon_Search备份"
            iconClass="icon_Search备份"
            class="icon_Search_second"
            >-{{ backSecond }}s</svg-icon
          >
        </span>
        <span class="play" @click="handlePauseOrPlay">
          <svg-icon
            name="pause"
            iconClass="pause"
            class="pause-icon"
            v-show="!paused"
            ref="pause"
          ></svg-icon>
          <svg-icon
            name="stop"
            iconClass="stop"
            class="pause-icon"
            v-show="paused"
            ref="stop"
          ></svg-icon>
        </span>
        <span class="next" @click="handleForward">
          <svg-icon
            name="icon_Search备份"
            iconClass="icon_Search备份"
            class="icon_fast_second"
          ></svg-icon>
        </span>
        <span>
          <svg-icon
            name="icon_volume"
            iconClass="icon_volume"
            class="icon_volume_first"
            @click="volumeFn(1)"
          ></svg-icon>
        </span>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: "index",
  props: {
    audioSrc: {
      type: String,
      default:
        "https://img-qn.51miz.com/Audio/2017/02/06/08/20170206081849_A100187_34f7e6b8-thumb.mp3",
    },
    backSecond: {
      type: Number,
      default: 3,
    },
    forwardSecond: {
      type: Number,
      default: 10,
    },
  },
  data() {
    return {
      duration: "00:00",
      currentDuration: "00:00",
      audio: "",
      paused: true,
      isMoveIn: false, //是否在移动中
    };
  },
  methods: {
    //后退
    handleBack() {
      if (this.audio.currentTime > this.backSecond) {
        this.audio.currentTime = this.audio.currentTime - this.backSecond;
      }
    },
    //前进
    handleForward() {
      if (this.audio.duration - this.audio.currentTime > this.forwardSecond) {
        this.audio.currentTime = this.audio.currentTime + 10;
      }
    },
    //暂停或播放
    handlePauseOrPlay() {
      this.audio.paused ? this.audio.play() : this.audio.pause();
      this.paused = !this.paused;
    },
    //视频在可以播放时触发
    getDuration() {
      this.duration = this.timeFormat(this.$refs.audio.duration);
      this.audio = this.$refs.audio;
    },
    //将单位为秒的的时间转换成mm:ss的形式
    timeFormat(number) {
      let minute = parseInt(number / 60);
      let second = parseInt(number % 60);
      minute = minute >= 10 ? minute : "0" + minute;
      second = second >= 10 ? second : "0" + second;
      return minute + ":" + second;
    },
    //进度条发生变化时触发
    updateTime() {
      if (!this.$refs.progress) return;
      this.currentDuration = this.timeFormat(this.audio.currentTime);
      //如果不是正在移动 和 没有暂停播放就执行
      if (!this.isMoveIn || !this.audio.paused) {
        // 设置当前时间
        let MoveX =
          this.$refs.progress.clientWidth *
          (this.audio.currentTime / this.audio.duration);
        //播放时更新距离
        this.$refs.currentProgress.style.width = MoveX + "px";
        this.$refs.circle.style.left =
          MoveX - this.$refs.circle.clientWidth / 2 + "px";
      }
    },
    //点击进度条更新进度
    clickProgress(e) {
      //如果不是正在移动 和 没有暂停播放就执行
      if (!this.isMoveIn || !this.audio.paused) {
        this.updateProgress(e.offsetX);
      }
    },
    //更新进度
    updateProgress(MoveX) {
      //当前移动的位置 = 当前移动的位置 / 当前进度条的可视长度    //this.$refs.progress.clientWidth 注意一定要拿总长度 否则会拿进度条已经走过的长度
      let clickProgress = MoveX / this.$refs.progress.clientWidth;
      //设置播放的时间 = 总时长 * 当前点击的长度
      this.audio.currentTime = this.audio.duration * clickProgress;
      //设置移动的位置
      this.$refs.currentProgress.style.width = MoveX + "px";
      this.$refs.circle.style.left =
        MoveX - this.$refs.circle.clientWidth / 2 + "px";
    },
    //鼠标弹起
    handleMouseup() {
      setTimeout(() => {
        this.audio.play();
        this.paused = false;
        this.isMoveIn = false;
      }, 200);
    },
    //小圆圈按下
    handleMousedown() {
      this.audio.pause();
      this.paused = true;
      this.isMoveIn = true;
      let progress = this.$refs.progress;
      //进度条 左 边距离页面左边的距离 移动最小值
      let moveMin = progress.offsetParent.offsetLeft + progress.offsetLeft;
      //进度条 右 边距离页面左边的距离 移动最大值
      let moveMax =
        progress.offsetParent.offsetLeft +
        progress.offsetLeft +
        progress.clientWidth;
      //小圆圈的宽度
      let circleWidth = this.$refs.circle.clientWidth / 2;
      let move = (move) => {
        if (move.pageX >= moveMax) {
          return;
        } else if (move.pageX <= moveMin) {
          return;
        }
        this.$refs.circle.style.left =
          move.pageX - moveMin - circleWidth + "px";
        this.updateProgress(move.pageX - moveMin);
      };
      //获取当前鼠标的位置 X
      document.addEventListener("mousemove", move);
      //鼠标弹起来
      document.addEventListener("mouseup", () => {
        document.removeEventListener("mousemove", move);
      });
    },
  },
};
</script>
<style scoped lang="less">
.card {
  width: 300px;
  padding: 30px;
  box-shadow: 0 0 10px 10px rgba(0, 0, 0, 0.03);
  border-radius: 10px;

  .progress {
    height: 7px;
    border-radius: 3px;
    margin-bottom: 5px;
    width: 100%;
    background-color: #dadfea;
    cursor: pointer;

    .currentProgress {
      position: relative;
      height: 100%;
      width: 0;
      background: linear-gradient(to right, #38deff, #ee8fff, #ffcf14);
      border-radius: 3px;

      .circle {
        position: absolute;
        right: -6px;
        top: -2px;
        display: inline-block;
        width: 10px;
        height: 10px;
        border-radius: 50%;
        border: 1px solid #3853fe;
        background-color: #fff;

        &:hover {
          width: 12px;
          height: 12px;
          top: -3px;
          border-radius: 50%;
        }
      }
    }
  }

  .time {
    display: flex;
    justify-content: space-between;
    color: #777a85;
    font-size: 12px;
  }

  .option {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px 30px 0 30px;

    .play,
    .pre,
    .next {
      display: flex;
      padding: 0 2px;
      align-items: center;
      cursor: pointer;
    }
  }
}
</style>

来看一下最终的效果:

当然,代码里边的icon你需要换成自己的,样式还可以自己再调整,不过最基础的功能已经具备了 。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Vue组件的方式来封装一个进度条,具体实现如下: ```html <template> <div class="progress-bar"> <div class="progress" :style="{ width: percentage + '%' }"></div> </div> </template> <script> export default { name: 'ProgressBar', props: { percentage: { type: Number, required: true, default: 0 } } } </script> <style> .progress-bar { width: 100%; height: 10px; background-color: #e0e0e0; border-radius: 5px; overflow: hidden; } .progress { height: 100%; background-color: #4caf50; transition: width 0.3s ease-in-out; } </style> ``` 在上述代码中,我们定义了一个名为`ProgressBar`的Vue组件,其中包含一个`percentage`属性,表示进度条的进度百分比。该组件使用CSS样式实现进度条的效果,具体实现如下: - `.progress-bar`:表示进度条的外层容器,包含背景色和边框样式。 - `.progress`:表示进度条的进度部分,包含进度条颜色和过渡效果。 在组件的模板中,我们使用`percentage`属性来计算进度条的宽度,并将其绑定到`.progress`样式的`width`属性上。这样,当`percentage`值发生变化时,进度条的宽度也会发生相应的变化。 使用该进度组件的方式如下: ```html <template> <div> <progress-bar :percentage="progress"></progress-bar> <button @click="increaseProgress">增加进度</button> </div> </template> <script> import ProgressBar from './ProgressBar.vue' export default { name: 'App', components: { ProgressBar }, data() { return { progress: 50 } }, methods: { increaseProgress() { this.progress += 10 } } } </script> ``` 在上述代码中,我们在父组件中引入了`ProgressBar`组件,并将`progress`属性绑定到子组件的`percentage`属性上。同时,在父组件中定义了一个按钮,点击按钮可以增加进度条的进度。 这样,我们就可以通过Vue组件封装一个进度条,并在其他组件中方便地重复使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值