微信小程序——音頻播放器

先來個效果圖韻下味:git

 

需求:github

  1. 音頻的播放,暫停,中間按鈕狀態的變化,播放時實時更新播放進度;
  2. 前進15s,後退15s;
  3. 進度條拖動。

 

一開始想着這3個功能應該挺簡單的。不就是播放,暫停,前進,後退麼~呵~寫的時候發現本身仍是太年輕。固然,這跟本身的技術功底有關係。如今把我遇到的難點及要注意的點說一下~小程序

  1. 須要設置一個名爲seekPosition的全局變量,初始值爲0。咱們要在播放的時候實時記錄播放的位置,存到該變量裏,這是方便在前進15s 或 後退15s 時計算時間點。
  2. 前進15s時要判斷剩餘時間是否>15s,若是<15s,則返回到開始位置;
  3. 後退15s時要判斷播放時間是否>15s,若是<15s,則返回到開始位置;
  4. 點擊播放時,要先判斷seekPisition是否>0,若是>0,則跳轉到seekPosition的位置,並播放;
  5. 拖動時,要先讓音頻中止播放,拖動結束後,再播放音頻。而且要計算拖動位置對應的時間。

 

完整代碼:app

wxml:ide

<view class=" audio-content">

  <image src="{{logo640x360}}" class="bg-blur"></image>
  <view class="bg-gray"></view>
  <view class="container-cover">
    <view class="cover">
      <image src="{{logo640x360}}" class="cover-image"></image>
      <view class="cover-tip">詞不達意.mp3</view>

    </view>
  </view>
  <view class="audio-inner row item-center">
    <view class="audio-desc">{{currentProcess}}</view>
    <view class="audio-progress-wrap">
      <van-slider value="{{sliderValue}}" step="{{sliderStep}}" active-color="#09bb07" use-button-slot bind:change="onSliderChange" bind:drag="onSliderDrag">
        <view class="slider-button" slot="button"></view>
      </van-slider>
    </view>
    <view class="audio-desc">{{productDetail.duration}}</view>
  </view>

  <!-- 播放器控制條 -->
  <section class="speech-player js_control_bar">
    <view class="player-bar row  justify-center item-center">
      <view class="backward js_audio_backward" title="後退15s">
        <ss-icon name="back-15" size="32px" color="#fff" block="{{true}}" bind:click="backward" />
      </view>
      <view class="play" title="播放/暫停">
        <view class="circle-loading" wx:if="{{loading}}"></view>
        <ss-icon name="play-outline" size="50px" color="#fff" block="{{true}}" wx:if="{{pause}}" bind:click="audioPlay" />
        <ss-icon name="pause-outline" size="50px" color="#fff" block="{{true}}" wx:if="{{playing}}" bind:click="audioPause" />
      </view>
      <view class="forward js_audio_forward" title="前進15s">
        <ss-icon name="forward-15" size="32px" color="#fff" block="{{true}}" bind:click="forward" />
      </view>
    </view>
  </section>
</view>

這裏面用到了有讚的小程序組件 icon組件 和 slider 組件。若是你要用的話把上面的 <ss-icon> 換成<van-icon>,而且須要本身找阿里矢量圖標庫查找對應的圖標。this

 

js:spa

// components/product/audio/index.js

let audioUrl = "",
  seekPosition = 0;
const audioContext = wx.createInnerAudioContext();

Component({
  options: {
    multipleSlots: true,
    addGlobalClass: true
  },


  /**
   * 組件的屬性列表
   */
  properties: {
    productId: Number,
  },
  /**
   * 組件的初始數據
   */
  data: {
    pause: true,
    playing: false,
    loading: false,
    productDetail: {},
    audioDuration: 0,
    currentProcess: '00:00',
    sliderStep:1
  },

  /**
   * 組件的方法列表
   */
  methods: {
    //音頻播放
    audioPlay(e) {
      const _this = this;
      let audioDuration = _this.data.audioDuration;
      if (audioUrl) {
        if (seekPosition) {
          //若是有指定位置,則跳轉到指定位置
          audioContext.seek(seekPosition);
        }
        audioContext.play();
        _this.setData({
          pause: false,
          playing: true,
          loading: false,
        })
      } else {
       //getJSON是我本身封裝的
        ss.getJSON('獲取音頻若是須要發送請求,這裏面放請求地址', {
          放你本身的參數
        }, res => {
          audioUrl = res.t;
          audioContext.src = audioUrl;
          if (seekPosition) {
            audioContext.seek(seekPosition);
          }
          audioContext.play();
          audioContext.onPlay(() => {
            console.log('onPlay')
          })

          audioContext.onWaiting(() => {
            console.log('onWaiting')
            _this.setData({
              pause: false,
              playing: false,
              loading: true,
            })
          })

          audioContext.onCanplay(() => {
            console.log('onCanplay')
            _this.setData({
              pause: false,
              playing: true,
              loading: false
            })
            setTimeout(() => {
              audioContext.duration
            }, 500)

            _this.audioStatus();
          })

          audioContext.onError((res) => {
            console.log(res.errMsg)
          })
        })
      }

    },


    //播放暫停
    audioPause: function() {
      const _this = this;
      audioContext.pause();
      _this.setData({
        pause: true,
        playing: false,
        loading: false
      })
    },

    //記錄播放狀態
    audioStatus: function() {
      const _this = this;
      //音頻播放進度更新事件
      audioContext.onTimeUpdate(() => {
        seekPosition = audioContext.currentTime;
        _this.setData({
          currentProcess: ss.formatSecToMin(audioContext.currentTime),
          sliderValue: audioContext.currentTime / _this.data.audioDuration * 100,
        })
      })
      //音頻播放結束
      audioContext.onEnded(() => {
        seekPosition = 0;
        _this.setData({
          sliderValue: 0,
          currentProcess: '00:00',
          playing: false,
          pause: true
        })
      })
    },

    //開始拖動
    onSliderDrag(e) {
      const _this = this;
      if (_this.data.playing) {
        _this.audioPause()
      }
      let sliderValue = e.detail.value;
      seekPosition = _this.data.audioDuration / 100 * sliderValue;
      _this.setData({
        currentProcess: ss.formatSecToMin(seekPosition)
      })

    },

    //拖動結束
    onSliderChange(e) {
      const _this = this;
      _this.audioPlay()
    },


    //前進15s
    forward() {
      const _this = this,
        audioDuration = _this.data.audioDuration;
      let currentTime;
      if (_this.data.playing) {
        currentTime = audioContext.currentTime;
      }
      if (_this.data.pause) {
        currentTime = seekPosition;
      }

      if (audioDuration - currentTime > 15) {
        seekPosition = currentTime + 15;
        _this.setData({
          sliderValue: seekPosition / audioDuration * 100,
          currentProcess: ss.formatSecToMin(seekPosition)
        });
      } else {
        seekPosition = audioDuration;
        _this.setData({
          sliderValue: 0,
          currentProcess: '00:00'
        });
      }
      if (audioUrl && _this.data.playing) {
        audioContext.seek(seekPosition);
      }
    },

    //後退15s
    backward() {
      const _this = this,
        audioDuration = _this.data.audioDuration;
      let currentTime;
      if (_this.data.playing) {
        currentTime = audioContext.currentTime;
      }
      if (_this.data.pause) {
        currentTime = seekPosition;
      }

      if (currentTime > 15) {
        seekPosition = currentTime - 15;
      } else {
        seekPosition = 0;
      }
      _this.setData({
        sliderValue: seekPosition / audioDuration * 100,
        currentProcess: ss.formatSecToMin(seekPosition)
      });
      if (audioUrl && _this.data.playing) {
        audioContext.seek(seekPosition);
      }
    }
  }
})

 

大概就是這些了~有更好解決方案的歡迎留言哈~~code

相關文章
相關標籤/搜索