微信小程序 封面旋转 音乐播放器的实现

 

最近在学习微信小程序的UI组件,audio音频方面想做一个类似网易云的播放效果。基础需求:

1、能控制音频开始、暂停、停止

2、音乐播放,封面旋转,音乐暂停封面停止旋转

3、能显示歌曲的播放时间和进度条

4、能通过进度条控制音乐的播放进度

 

先上一张效果图

直接放代码,代码里面写了比较多的注释。

wxml:

<view class='item'>
    <text>音乐播放器</text>
    <image class='audio_post{{music_on?" music_on":""}}'  style="animation-play-state:{{music_playing?'running':'paused'}}" src='http://y.gtimg.cn/music/photo_new/T002R300x300M000003rsKF44GyaSk.jpg?max_age=2592000' ></image>

    <view class='audio_progress'>
      <slider block-size='14' bindchange='audioChange' bindchanging='audioChanging' value='{{sliderValue}}'></slider>
      <view>{{musicTime}}</view>
    </view>
    <view class='audio_control'>
      <button type='primary' bindtap='playMusic'>播放</button>
      <button type='primary' bindtap='pauseMusic'>暂停</button>
      <button type='primary' bindtap='stopMusic'>停止</button>
    </view>
    
  </view>

wxss:

.item {
  width: 100%;
  padding-bottom: 30rpx;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.item text {
  font-size: medium;
}

.audio_progress{
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: space-around;

}

.audio_progress slider{
  width: 80%;
}

.audio_progress view{
  padding: 18rpx;
}

.audio_post{
  width: 300rpx;
  height: 300rpx;
  margin: 50rpx auto;
  border-radius: 50%;
}

/* 旋转的样式 */
.music_on{
  animation: audio-rotate 8s linear infinite;
}

.audio_control{
  display: flex;
  flex-direction: row;
  justify-content:space-around;

}

.audio_control button{
  width:200rpx;
  height:80rpx; 
  line-height:80rpx;
}

/* 旋转动画 */
@keyframes audio-rotate {
  0% {
    transform: rotateZ(0deg);
  }

  100% {
    transform: rotateZ(360deg);
  }
}

js 

//InnerAudioContext实例
var audioCxt;
//动画
var audioAnimation;
audioCxt = wx.createInnerAudioContext();
audioCxt.src = 'http://ws.stream.qqmusic.qq.com/M500001VfvsJ21xFqb.mp3?guid=ffffffff82def4af4b12b3cd9337d5e7&uin=346897220&vkey=6292F51E1E384E06DCBDC9AB7C49FD713D632D313AC4858BACB8DDD29067D3C601481D36E62053BF8DFEAF74C0A5CCFADD6471160CAF3E6A&fromtag=46';

Page({

  /**
   * 页面的初始数据
   */
  data: {
    audioAnimation : null,
    //音乐是不是开始
    music_on : true,
    //音乐是不是在播放
    music_playing :false,
    //显示的时间
    musicTime : '00:00',
    sliderValue : 0
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    //音乐播放结束触发
    audioCxt.onEnded((res) =>{
      //修改属性。去除css状态
      this.data.music_on = false;
      this.setData({
        music_on: this.data.music_on
      })
      //重新播放
      audioCxt.seek(0);
      this.setData({
        musicTime: '00:00',
        sliderValue: 0
      })
    }),
    //在播放状态,绑定播放进度更新事件。然后控制进度条和时间显示
    audioCxt.onPlay((res) =>{ 
      audioCxt.onTimeUpdate(this.timeUpdate)
    })
  },

  //播放按钮事件
  playMusic : function(){
    this.data.music_on = true; 
    this.data.music_playing = true;
    audioCxt.play();
    //图片添加css样式,旋转样式
    this.setData({
      music_on: this.data.music_on,
      music_playing: this.data.music_playing
    })
  },

  //暂停按钮事件
  pauseMusic : function(){
    this.data.music_on = true;
    this.data.music_playing = false;
    audioCxt.pause();
    this.setData({
      music_on: this.data.music_on,
      music_playing: this.data.music_playing
    })
  },

  //停止按钮事件
  stopMusic : function(){
    audioCxt.stop();
    this.data.music_on = false;
    this.setData({
      music_on: this.data.music_on
    })
  },

  //进度条改变后触发事件
  audioChange : function(e){
    var length = audioCxt.duration;
    var percent = e.detail.value;
    //用进度条百分比 * 整个音乐长度
    var musicTime = Math.round(length/100*percent);
    audioCxt.seek(musicTime);

    //因为在拖动进度条时,去除了时间绑定,所以进度改变后重新绑定
    audioCxt.onTimeUpdate(this.timeUpdate);

    this.setData({
      musicTime: this.musicTimeFormat(musicTime)
    })
  },
  //进度条拖动过程中触发事件
  audioChanging : function(e){
    //因为在进度条拖动的时候,还会在timeUpdate里面修改进度条的value,倒置拖动受影响,所以当拖动的时候需要取消绑定
    audioCxt.offTimeUpdate();

    //拖动时修改时间显示
    var length = audioCxt.duration;
    var percent = e.detail.value;
    var musicTime = Math.round(length / 100 * percent);
    this.setData({
      musicTime: this.musicTimeFormat(musicTime)
    })
  },

  //将秒钟转化为mm:ss的时间格式
  musicTimeFormat : function(time){
    var second = Math.floor(time % 60);
    if(second<10){
      second = '0' + second;
    }
    var minute = Math.floor(time / 60);
    if (minute < 10) {
      minute = '0' + minute;
    }
    return minute + ':' + second;
  },

  //播放的时候,更新进度条和时间显示
  timeUpdate : function(){
    var time = audioCxt.currentTime;
    var percent = Math.round(time / audioCxt.duration * 100);
    this.setData({
      musicTime: this.musicTimeFormat(time),
      sliderValue: percent
    })
  }
})

总结几个难点吧。

1、audio控件小程序已经不再更新了。都使用InnerAudioContext这个对象来控制音频。这个方法没有默认界面,需要自己写界面。

2、封面的旋转使用的css中的keyframes来进行的,用animation也尝试过,感觉比较复杂并且不好操作。用css来实现比较简单方便。

3、style="animation-play-state:{{music_playing?'running':'paused'}}"  这一个属性能控制动画暂停。有帖子说在IOS真机上会出现问题,没有苹果手机没进行测试。这个属性文档里面都没有找到。

4、进度条和播放的状态要进行双向绑定,播放的时候进度条的value要改变,进度条拖动的时候播放的时间也要进行改变。

5、自己有时候写变量还是不太规范。没形成自己的一套规则。

大家有什么疑问欢迎留言提问,多多交流。