H5 使用audio 实现语音播放 并显示语音时长 可快进、快退

以vue示例:

效果

<template>
  <div class="voice-box">
    <audio
      ref="audio"
      @pause="onPause"
      @play="onPlay"
      @timeupdate="onTimeupdate"
      @loadedmetadata="onLoadedmetadata"
      controls="controls"
      style="display:none;"
      :src="imgUrl + '从后台获取的地址'"
    >
      <!-- <source :src="imgUrl + questionData.voiceAddress" /> -->
      <!-- <source src="@/assets/测试语音.mp3" /> -->
    </audio>

    <!-- 音频播放控件 -->
    <div>
      <button @click="startPlayOrPause" class="play-btn" :class="{'btn-pause': audio.playing}"></button>
      <!-- 当前时间 -->
      <span class="time">{{ audio.currentTime | formatSecond}}</span>
      <!-- 语音条 -->
      <div class="slider-box">
        <div class="slider" @touchstart="handleTouchStart">
          <div class="slider-track"></div>
          <div class="slider-fill" :style="'width:'+sliderTime+'%'"></div>
          <div class="slider-thumb" :style="'left:'+sliderTime+'%'"></div>
        </div>
      </div>
      <!-- 总时长 -->
      <span class="time">{{ audio.maxTime | formatSecond}}</span>
    </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)
      ("0" + mimute).slice(-2) + ":" + ("0" + second).slice(-2)
    );
  } else {
    return "00:00";
  }
}

export default {
  data() {
    return {
      imgUrl: "http://xxx",
      sliderTime: 0,
      audio: {
        // 该字段是音频是否处于播放状态的属性
        playing: false,
        // 音频当前播放时长
        currentTime: 0,
        // 音频最大播放时长
        maxTime: 0,
        minTime: 0,
        step: 0.1
      }
    };
  },
  methods: {
    // 控制音频的播放与暂停
    startPlayOrPause() {
      return this.audio.playing ? this.pause() : this.play();
    },
    // 播放音频
    play() {
      this.$refs.audio.play();
    },
    // 暂停音频
    pause() {
      this.$refs.audio.pause();
    },
    // 当音频播放
    onPlay() {
      this.audio.playing = true;
    },
    // 当音频暂停
    onPause() {
      this.audio.playing = false;
    },
    // 当加载语音流元数据完成后,会触发该事件的回调函数
    // 语音元数据主要是语音的长度之类的数据
    onLoadedmetadata(res) {
      this.audio.maxTime = parseInt(res.target.duration);
    },
    // 当timeupdate事件大概每秒一次,用来更新音频流的当前播放时间
    // 当音频当前时间改变后,进度条也要改变
    onTimeupdate(res) {
      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);
    },

    handleTouchStart(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);

      // e.preventDefault();
      // this.onDragStart(e);
    },
    handleTouchMove(e) {
      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);
      // this.onDragStop(e);
    },
    // 从点击位置更新 value
    setValue(e) {
      const $el = this.$el;
      const { maxTime, minTime, step } = this.audio;
      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) {
      // this.audio.playing && this.pause();
      // console.log('拖动了',index,this.sliderTime,this.audio.maxTime,parseInt(index / 100 * this.audio.maxTime))
      // !this.audio.playing && this.play();
      this.$refs.audio.currentTime = parseInt(
        (index / 100) * this.audio.maxTime
      );
    }
  },
  filters: {
    // 使用组件过滤器来动态改变按钮的显示
    transPlayPause(value) {
      return value ? "暂停" : "播放";
    },
    // 将整数转化成时分秒
    formatSecond(second = 0) {
      return realFormatSecond(second);
    }
  }
};
</script>
<style lang="less">
.voice-box {
  background: #ffba00;
  padding: 0 20px;
  .play-btn {
    width: 28px;
    height: 30px;
    background: url("../../assets/images/listen/play.png") no-repeat center -3px;
    background-size: 100% 100%;
    margin-right: 20px;
    &.btn-pause {
      background: url("../../assets/images/listen/pause.png") no-repeat center -2px;
      background-size: 100% 100%;
    }
  }
  .time {
    font-size: 20px;
  }
  .slider-box {
    display: inline-block;
    margin: 0 30px;
  }
  .slider {
    width: 360px;
    position: relative;
    top: -5px;
    height: 24px;
    display: flex;
    align-items: center;
    cursor: default;
    user-select: none;
    outline: none;
  }

  .slider-track {
    position: absolute;
    height: 20px;
    left: 0;
    right: 0;
    top: 50%;
    margin-top: -1px;
    background-color: rgba(255, 255, 255, 0.3);
  }

  .slider-fill {
    position: absolute;
    width: 20px;
    height: 19px;
    background-color: #fff;
    left: 0;
    top: 50%;
    margin-top: -1px;
  }

  .slider-thumb {
    position: absolute;
    top: 85%;
    width: 20px;
    height: 21px;
    background-color: #fff;
    color: #fff;
    // border-radius: 50%;
    transform: translate(-50%, -50%);
    cursor: pointer;
  }
}
</style>

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值