"音乐"小程序:播放器

来自CloudWiki
跳转至: 导航搜索

任务分析

播放器是显示在content区域中的第2个标签页,对应的<swiper-item>的索引为1,

其页面内容由3部分组成,音乐信息、专辑封面和播放进度.

前导知识

音频API

微信小程序提供了播放音频的API ,

通过创建一个InnerAudioContext实例来完成具体工作:

  var audioCtx = wx.createInnerAudioContext()

示例:

js代码:

 /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
     //创建实例
     var audioCtx = wx.createInnerAudioContext()
     //设置地址
     audioCtx.src='https://www.ytmp3.cn/down/76677.mp3'
     //当开始播放时,输出调试信息
     audioCtx.onPlay(function(){
        console.log('开始播放')
     })
     //当发生错误时,输出调试信息
     audioCtx.onError(function(res) {
        console.log(res.errMsg)   //错误信息
        console.log(res.errCode)  //错误码
     })
     //开始播放
     audioCtx.play()
  },

效果:当页面打开后,音乐会自动播放

slide组件

slider组件是小程序表单组件中的一种,用于滑动选择某一个值,

在本项目中将用来实现播放器的进度条。

常用属性:

  • bindchanging:拖动过程中触发的事件。

wxml:

 
<slider bindchanging="sliderChanging" show-value />

js:

 sliderChanging: function(e) {
    console.log(e.detail.value)
 },

效果:

Python21081702.png

Python21081703.png

定义基础数据

在index.js中的data对象定义基础数据playlist,主要包括音乐的信息和音乐播放路径

  • playlist是歌曲列表,
  • playIndex 是歌曲索引值,
  • play对象记录了当前播放曲目的信息。
 data: {

    // 播放列表数据
    playlist: [{
      id: 1,
      title: '野花香',
      singer: '莫斯曼',
      src: 'https://www.ytmp3.cn/down/75810.mp3',
      coverImgUrl: '/images/cover.jpg'
    }, {
      id: 2,
      title: '梦中的额吉',
      singer: '广场舞',
      src: 'https://www.ytmp3.cn/down/73552.mp3',
      coverImgUrl: '/images/cover.jpg'
    }, {
      id: 3,
      title: '别哭了宝贝',
      singer: '皓天',
      src: 'https://www.ytmp3.cn/down/73421.mp3',
      coverImgUrl: '/images/cover.jpg'
    }, {
      id: 4,
      title: '桃花多多开',
      singer: '阿牛',
      src: 'https://www.ytmp3.cn/down/73418.mp3',
      coverImgUrl: '/images/cover.jpg'
    }],
    state: 'paused',
    playIndex: 0,
    play: {
      currentTime: '00:00',
      duration: '00:00',
      percent: 0,
      title: '',
      singer: '',
      coverImgUrl: '/images/cover.jpg',
    }
  },


编写播放器页面

播放器页面主要用于展示当前播放曲目的信息,


wxml

           <!-- 播放器 -->
            <view class="content-play">
                  <!-- 显示音乐信息 -->
                  <view class="content-play-info">
                    <text>{{play.title}}</text>
                    <view>—— {{play.singer}} ——</view>
                  </view>
                  <!-- 显示专辑封面 -->
                  <view class="content-play-cover">
                    <image src="{{play.coverImgUrl}}" style="animation-play-state:{{state}}" />
                  </view>
                  <!-- 显示播放进度和时间 -->
                  <view class="content-play-progress">
                    <text>{{play.currentTime}}</text>
                    <view>
                      <slider bindchange="sliderChange" activeColor="#d33a31" block-size="12" backgroundColor="#dadada" value="{{play.percent}}" />
                    </view>
                    <text>{{play.duration}}</text>
                  </view>
            </view>

CSS

/* pages/play/index.wxss */
page {
  display: flex;
  flex-direction: column;
  background: #17181a;
  color: #ccc;
  height: 100%;
}

.content {
  flex: 1;
}

.content > swiper {
  height: 100%;
}
.content-info {
  height: 100%;
}

::-webkit-scrollbar {
  width: 0;
  height: 0;
  color: transparent;
}

/* 播放器 */

.content-play {
  display: flex;
  justify-content: space-around;
  flex-direction: column;
  height: 100%;
  text-align: center;
}

.content-play-info > view {
  color: #888;
  font-size: 11pt;
}
/* 显示专辑页面样式 */

.content-play-cover image {
  animation: rotateImage 10s linear infinite;
  width: 400rpx;
  height: 400rpx;
  border-radius: 50%;
  border: 1px solid #333;
}

@keyframes rotateImage {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

/* 播放进度和时间 */

.content-play-progress {
  display: flex;
  align-items: center;
  margin: 0 35rpx;
  font-size: 9pt;
  text-align: center;
}

.content-play-progress > view {
  flex: 1;
}


效果图

Wexin21081701.png

实现音乐播放功能

音乐播放功能 主要创建一个InnerAudioContext实例,

然后利用实例的属性和方法来实现音乐控制。

WXML

 
<!-- 底部播放器 -->
<view class="player">
  <image class="player-cover" src="{{play.coverImgUrl}}" />
  <view class="player-info">
    <view class="player-info-title">{{play.title}}</view>
    <view class="player-info-singer">{{play.singer}}</view>
  </view>
  <view class="player-controls">
    <!-- 切换到播放列表 -->
    <image src="/images/01.png" bindtap="changePage" data-page="2" />
    <!-- 播放或暂停 -->
    <image wx:if="{{state=='paused'}}" src="/images/02.png" bindtap="play" />
    <image wx:else src="/images/02stop.png" bindtap="pause" />
    <!-- 下一曲 -->
    <image src="/images/03.png" bindtap="next" />
  </view>
</view>

CSS


/* 底部播放器 */

.player {
  display: flex;
  align-items: center;
  background: #222;
  border-top: 1px solid #252525;
  height: 112rpx;
}

.player-cover {
  width: 80rpx;
  height: 80rpx;
  margin-left: 15rpx;
  border-radius: 8rpx;
  border: 1px solid #333;
}

.player-info {
  flex: 1;
  font-size: 10pt;
  line-height: 38rpx;
  margin-left: 20rpx;
  padding-bottom: 8rpx;
}

.player-info-title {
  color: #ccc;
}

.player-info-singer {
  color: #888;
}

.player-controls image {
  width: 80rpx;
  height: 80rpx;
  margin-right: 15rpx;
}

效果图:

Wexin21081611.png


JS

onReady函数:

// 实现播放器播放功能
  audioCtx: null,
  onReady: function() {
    this.audioCtx = wx.createInnerAudioContext()
    // 默认选择第1曲
    this.setMusic(0)
 //  this.audioCtx.play()
  //  this.setData({
  //    state: 'running'
  //  })
    var that = this
    // 播放进度检测
    this.audioCtx.onError(function() {
      console.log('播放失败:' + that.audioCtx.src)
    })
    // 播放完成自动换下一曲
    this.audioCtx.onEnded(function() {
      that.next()
    })
    // 自动更新播放进度
    this.audioCtx.onPlay(function() {})
    this.audioCtx.onTimeUpdate(function() {
      that.setData({
        'play.duration': formatTime(that.audioCtx.duration),
        'play.currentTime': formatTime(that.audioCtx.currentTime),
        'play.percent': that.audioCtx.currentTime / that.audioCtx.duration * 100
      })
    })
    // 格式化时间
    function formatTime(time) {
      var minute = Math.floor(time / 60) % 60;
      var second = Math.floor(time) % 60
      return (minute < 10 ? '0' + minute : minute) + ':' + (second < 10 ? '0' + second : second)
    }
  },


setMusic函数:

  // 音乐播放
  setMusic: function(index) {
    var music = this.data.playlist[index]
    this.audioCtx.src = music.src
    this.setData({
      playIndex: index,
      'play.title': music.title,
      'play.singer': music.singer,
      'play.coverImgUrl': music.coverImgUrl,
      'play.currentTime': '00:00',
      'play.duration': '00:00',
      'play.percent': 0
    })
  },

按钮事件


  // 播放按钮
  play: function() {
    this.audioCtx.play()
    this.setData({
      state: 'running'
    })
  },

  // 暂停按钮
  pause: function() {
    this.audioCtx.pause()
    this.setData({
      state: 'paused'
    })
  },
  // 下一曲按钮
  next: function() {
    var index = this.data.playIndex >= this.data.playlist.length - 1 ? 0 : this.data.playIndex + 1
    this.setMusic(index)
    if (this.data.state === 'running') {
      this.play()
    }
  },

效果:

点击’播放‘、’暂停‘、’下一曲‘时有不同的效果。

控制播放进度

在slider组件上绑定bindchange事件,可以实现滑动进度条调节音乐播放进度。

  <slider bindchange="sliderChange" activeColor="#d33a31" block-size="12" backgroundColor="#dadada" value="{{play.percent}}" />
    

在index.js中编写sliderChange函数获取用户当前选择的进度

  // 滚动条调节歌曲进度
  sliderChange: function(e) {
    var second = e.detail.value * this.audioCtx.duration / 100
    this.audioCtx.seek(second)
  },

效果:

Wexin21081702.png

WANZHENG

music_title

index.wxml:

<view class="content">
      <view class="music_title">
          <view class="music_name">踏雪寻卿</view>
          <view class="music_singer">--董真--</view>
      </view>
      <view class="music_cover"></view>
      <view class="music_control"></view>
</view>

index.wxss:

/* pages/player/index.wxss */
.content{
  width: 750rpx;
  height:auto;
   display:flex;
   flex-direction: column;
   /* background-color: */
}
.music_title{
  width:100%;
  height:200rpx;
  /* border:4rpx solid red;
  background:yellow; */
  text-align:center;
}
.music_name{
   font-size: 40rpx;
   font-weight: bold;
   margin-top:30rpx;
}
.music_singer{
  font-size: 36rpx;
  margin-top:16rpx;
}
.music_cover{
  width:100%;
  height:800rpx;
  border:4rpx solid red;
  background:green;
}
.music_control{
  width:100%;
  height:150rpx;
  border:4rpx solid red;
  background:blue;
}


全部代码

wxml

<!--pages/player/index.wxml-->
<view class="content">
      <view class="music_title">
          <view class="music_name">踏雪寻卿</view>
          <view class="music_singer">--董真--</view>
      </view>
       <view class="music_cover">
          <view class="music_img">
               <image src="/images/rec1.png" ></image>
          </view>
          <view class="music_progress">
            <text>00:00</text>
            <view>
            <slider bindchanging="sliderChanging" activeColor="#d33a31" block-size="20" backgroundColor="#dadada"  />
          </view>
            <text>00:00</text>
          </view>
      </view>
      <view class="music_control">
           <view class="music_nail">
               <image src="/images/rec1.png" style="width:145rpx;height:145rpx"></image>
           </view>
           <view class="music_info">
                <view class="name">踏雪寻卿</view>
                <view class="singer">董真</view>
           </view>
           <view class="music_button">
            <button bindtap='audioPlay'>播放</button>
            <button bindtap='audioPause'>暂停</button>
            <button bindtap='audioPlayBack'>回放</button>
           </view>
      </view>
</view>

wxss

/* pages/player/index.wxss */
.content{
  width: 750rpx;
  height:auto;
   display:flex;
   flex-direction: column;
   /* background-color: */
}
.music_title{
  width:100%;
  height:200rpx;
  /* border:4rpx solid red;
  background:yellow; */
  text-align:center;
}
.music_name{
   font-size: 40rpx;
   font-weight: bold;
   margin-top:30rpx;
}
.music_singer{
  font-size: 36rpx;
  margin-top:16rpx;
}
.music_cover{
  width:100%;
  height:700rpx;
  /* border:4rpx solid red;
  background:green; */
  display: flex;
  flex-direction: column;
  text-align: center;
}
.music_cover image{
  width: 400rpx;
  height: 400rpx;
  margin-top:80rpx;
  /* animation-play-state: false;
  animation: rotateImage 10s linear infinite; */
  border-radius: 50%;
  border: 1px solid #333;
}

@keyframes rotateImage {
  from {
    transform: rotate(0deg);
  }
 to {
    transform: rotate(360deg);
  }
}
.music_progress{

 text-align: center;
 display: flex;
 align-items: center;
  margin: 50rpx 35rpx;
  font-size: 30rpx;

}
.music_progress > view {
  flex: 1;
}

.music_control{
  width:100%;
  height:150rpx;
  /* border:4rpx solid red;
  background:blue; */
  display: flex;

}
.music_nail{
  /* border:3rpx solid red; */
  width:150rpx;
}
.music_info{
  /* border:3rpx solid red; */
  width:300rpx;
  line-height: 50rpx;
}
.music_info .name{
  font-size:30rpx;font-weight: bold;
}
/* .music_info .singer{
  
} */
.music_button{
  /* border:3rpx solid red; */
  width:290rpx;
  display:flex;
}
.music_button button{
  width:90rpx;
}

js

sliderChanging: function(e) {
    console.log(e.detail.value)
 },