uniapp之音频播放器

感谢写开源组件的小哥 我做了些调整供大家参考

1.解决滑动卡顿bug 加了防抖

2.滑动进度条时 先暂停再播放 就不会出现卡顿

3.初始化时 要onCanplay钩子中 setInterval 获取音频文件长度 不然会显示 0

*如何使用 更改porps 传入的node对象中的src, 我这的是node.attr.src

上图

<template>

  <view class="audio-component">

    <view class="audio-slider">

      <view class="img-box" @click="playAudio">

        <van-icon v-show="!state" name="play-circle" size="80rpx" color="#fed723" />

        <van-icon v-show="state" name="pause-circle" size="80rpx" color="#fed723" />

      </view>

      <slider

        block-size="14"

        :value="sliderProgressValue"

        @change="sliderChange"

        min="0"

        :max="sliderMax"

        activeColor="#12C489"

        block-color="#12C489"

        step="1"

      />

      <view class="time-Show">{
   
   { currentTimeStr }}/{
   
   { sliderValue }}</view>

    </view>

  </view>

</template>

<script>

export default {

  name: "wxParseAudio",

  props: {

    node: {

      type: Object,

      default: () => {},

    },

  },

  data() {

    return {

      sliderMax: "", //  例如30     音频总时长

      sliderProgressValue: 0, //  例如11     实时进度

      sliderValue: "00:00", //  例如00:30 最大值

      currentTimeStr: "00:00", //  例如00:11 音频实时播放进度

      innerAudioContext: null, //  实例

      state: false, //  播放状态  false暂停   true播放

    };

  },

  watch: {

    //监听用户点击播放的数据变动

    node: {

      immediate: true, // 加此属性

      handler: function (item) {

        console.log("监听", item);

        this.sliderProgressValue = 0;

        this.currentTimeStr = "00:00";

        // 重置 销毁1

        if (this.innerAudioContext) {

          this.innerAudioContext.destroy();

        }

        if (item) {

          this.innerAudioContext = uni.createInnerAudioContext();

          this.state = false;

          this.innerAudioContext.autoplay = false; //设置是否自动播放

          this.innerAudioContext.obeyMuteSwitch = false; //是否遵循系统静音开关,当此参数为 false 时,即使用户打开了静音开关,也能继续发出声音,默认值 true

          this.innerAudioContext.sessionCategory = "soloAmbient"; //在后台时不播放,如有其他播放,会暂停其他播放(但在移动端h5中 后台不播放失效)

          this.innerAudioContext.src = item.attr.src; //'http://*******/files/download/sound1/206/1638.mp3';//音频的url

          this.innerAudioContext.onCanplay((v) => {

            console.log(v, this.innerAudioContext);

          });

          this.creatAudio();

        }

      },

      deep: true, //深度监听

    },

  },

  methods: {

    throttle(fn, wait) {

      let previous = 0;

      return function (...arg) {

        let context = this;

        let now = Date.now();

        //每隔一段时间执行一次;

        if (now - previous > wait) {

          fn.apply(context, arg);

          previous = now;

        }

      };

    },

    // 点击播放事件

    playAudio() {

      this.state = !this.state;

      // false暂停  true播放

      if (this.state) {

        this.innerAudioContext.play(); //播放

        this.creatAudio(); //获取播放时长进度

      } else {

        this.innerAudioContext.pause(); //暂停

      }

    },

    //实时播放时长

    creatAudio() {

      this.innerAudioContext.onCanplay(() => {

        let intervalID = setInterval(() => {

          if (this.innerAudioContext.duration !== 0) {

            clearInterval(intervalID);

            console.log("音频时长", this.innerAudioContext.duration);

            this.sliderValue = this.formatSecond(this.innerAudioContext.duration);

          }

        }, 500);

      });

      this.innerAudioContext.onSeeked(() => {

        this.innerAudioContext.pause();

        this.innerAudioContext.play();

        this.state = true;

      });

      // 防抖

      const withThrottle = this.throttle(() => {

        const {currentTime, duration} = this.innerAudioContext; //这俩参数是这个api自带的参数, 解构

        console.log(currentTime);

        let currTimeStr = this.formatTime(currentTime);

        // 未转化 时间格式的实时时长

        this.sliderProgressValue = Math.floor(currentTime);

        this.sliderMax = Math.floor(duration);

        // 实时变动的时间

        this.currentTimeStr = currTimeStr;

        //音频总时长

        this.sliderValue = this.formatSecond(duration);

        // console.log('时长',this.sliderProgressValue,this.currentTimeStr,currentTime,duration)

      }, 1000);

      // 播放中的实时监听 播放位置 以及时长

      this.innerAudioContext.onTimeUpdate(withThrottle);

      // 监听播放结束 的处理

      this.innerAudioContext.onEnded(() => {

        console.log("播放结束");

        setTimeout(() => {

          // this.currentTimeStr = this.sliderValue;

          // this.sliderProgressValue = 0;

          this.sliderProgressValue = 0;

          this.currentTimeStr = "00:00";

          this.state = false;

        }, 300);

      });

    },

    //格式化时间格式

    formatTime(num) {

      num = Math.floor(num);

      let second = num % 60;

      if (second < 10) second = "0" + second;

      let min = Math.floor(num / 60);

      if (min < 10) min = "0" + min;

      return min + ":" + second;

    },

    // 拖拽音频播放位置

    sliderChange(e) {

      // console.log('value 发生变化:' + e.detail.value,this.state,this.innerAudioContext)

      const currTimeStr = this.formatTime(e.detail.value);

      this.currentTimeStr = currTimeStr;

      // 播放进度条位置

      this.sliderProgressValue = e.detail.value;

      //设置要播放的位置

      this.innerAudioContext.seek(e.detail.value);

      // this.innerAudioContext.pause()//暂停

      // // 因为拖拽后自动播放 导致实时获取播放时间的方法没有执行【坑点】

      // setTimeout(()=>{

      //  //模拟点击播放

      //  this.state=false

      //  this.playAudio()

      // },1000)

    },

    formatSecond(seconds) {

      var h =

        Math.floor(seconds / 3600) < 10

          ? "0" + Math.floor(seconds / 3600)

          : Math.floor(seconds / 3600);

      var m =

        Math.floor((seconds / 60) % 60) < 10

          ? "0" + Math.floor((seconds / 60) % 60)

          : Math.floor((seconds / 60) % 60);

      var s =

        Math.floor(seconds % 60) < 10

          ? "0" + Math.floor(seconds % 60)

          : Math.floor(seconds % 60);

      // return  h + ":" + m + ":" + s;

      return m + ":" + s;

    },

    // 关闭

    close() {

      if (this.innerAudioContext) {

        this.innerAudioContext.destroy();

      }

      this.sliderMax = ""; //  例如30     音频总时长

      this.sliderProgressValue = 0; //  例如11     实时进度

      this.sliderValue = "00:00"; //  例如00:30 最大值

      this.currentTimeStr = "00:00"; //  例如00:11 音频实时播放进度

      this.innerAudioContext = null; //  实例

      this.state = false;

      this.$emit("AudioDestroy", "关闭");

    },

  },

  // 组件销毁 同时销毁音频

  destroyed() {

    if (this.innerAudioContext) {

      this.innerAudioContext.destroy();

    }

  },

};

</script>

<style lang="less" scoped>

.audio-component {

  background-color: #f5f3f3;

  padding: 20rpx;

  border-radius: 4px;

  // position: fixed;

  // width: calc(100% - 60rpx);

  // left: 0;

  // bottom: 120rpx;

  // margin: 0 30rpx;

}

.audio-slider {

  display: flex;

  align-items: center;

  slider {

    flex: 1;

    margin: 6rpx 40rpx 6rpx 20rpx;

  }

  .img-box {

    width: 80rpx;

    // background-color: red;

    display: flex;

    align-items: center;

    justify-content: center;

    .laba {

      width: 60rpx;

      height: 60rpx;

    }

  }

}

.time-Show {

  color: #9a9b9d;

}

.close-box {

  width: 35rpx;

  height: 35rpx;

  margin-right: 25rpx;

  image {

    width: 35rpx;

    height: 35rpx;

  }

}

.text-content {

  display: flex;

  color: #9a9b9d;

  justify-content: space-between;

  padding: 0 90rpx 0 90rpx;

}

</style>

猜你喜欢

转载自blog.csdn.net/weixin_72222776/article/details/129762928