音乐播放器的功能是通过调用微信小程序的
wx.createInnerAudioContext()
接口获取对象
ctx
,然后利用
ctx
对象的属性和方法来实现音乐控制。
本例会涉及到
ctx
对象的如下属性、方法,更多可以访问
这里。
- src,音频资源的地址。
值得注意的是,src目前仅支持根路径,不支持相对路径。如果使用相对路径,会导致音频无法播放,同类问题可参见这里。
这也是为什么本例会基于express搭建一个小型服务器。 - volume,音量,范围0~1,默认是1。
- duration,当前音频的长度,单位是秒。
- currentTime,当前音频的播放位置,单位是秒。
- paused,布尔值,只读,音频当前是否是暂停或停止状态。
- play(),播放音频。
- pause(),暂停音频。暂停后的音频再次播放时会从在暂停处开始播放。
- onEnded(callback),音频播放至结束时会触发。
- onTimeUpdate(callback),音频播放过程中该事件会不断被触发(实际开发中,发现常常无法触发onTimeUpdate,即使音频的确处于播放状态,后面会提供解决方法)。
- onCanPlay(callback),音频一旦进入 可以播放 状态,就会触发该事件。我们就是通过在这个方法中不断读取
paused
值来解决onTimeUpdate触发失效问题,更多可以参考这里。
搭建音频服务器
关于服务器搭建,可以参考这里。
-
目录结构
-
下载express
npm install --save-dev express
- start.js,启动代码
//start.js
const express = require("express");
const server = express();
server.use(express.static("public"));
server.listen(8080,function(){
console.log("listening on port:8080");
})
- 启动服务器,
npm run start
微信小程序代码
<!--index.wxml-->
<view class="container">
<image class="play-icon" wx:if="{{isRunning}}" src="../../images/暂停.png" bindtap="pause"></image>
<image class="play-icon" wx:else src="../../images/播放.png" bindtap="start"></image>
<view class="text">
<text>{{currentTime}}</text> / <text>{{duration}}</text>
</view>
<slider value="{{currentValue}}" activeColor="#000000" block-size="10" bindchange="change"></slider>
<image class="volumn-icon" wx:if="{{isMute}}" src="../../images/静音.png" bindtap="speak"></image>
<image class="volumn-icon" wx:else src="../../images/音量.png" bindtap="mute"></image>
</view>
/**index.wxss**/
page{
background-color: #000;
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}
.container{
margin: 20rpx;
background-color: #fff;
display: flex;
align-items: center;
height: 120rpx;
padding: 60rpx;
box-sizing: border-box;
border-radius: 60rpx;
}
.container slider{
flex: 1;
}
.container .play-icon{
width: 64rpx;
height: 64rpx;
margin-left: -30rpx;
margin-right: 30rpx;
}
.container .volumn-icon{
width: 64rpx;
height: 64rpx;
margin-right: -20rpx;
}
.container .text{
font-size: 26rpx;
}
.container:hover{
background-color: #eee;
}
// index.js
Page({
data:{
currentTime:"00:00",
duration:"04:00",
isRunning:false,
currentValue:0,
isMute:false
},
ctx:null,
onReady:function(){
this.ctx = wx.createInnerAudioContext();
this.ctx.src = "http://localhost:8080/songs/不要说话.mp3";
this.ctx.onEnded(()=>{
console.log("播放结束");
this.setData({
isRunning:false
})
})
this.ctx.onCanplay(() => {
console.log(this.ctx.paused);
})
this.ctx.onTimeUpdate(() => {
console.log("volumn:",this.ctx.volume);
this.setData({
currentTime:formatTime(this.ctx.currentTime),
duration:formatTime(this.ctx.duration),
currentValue:Math.floor(100*this.ctx.currentTime/this.ctx.duration)
})
})
function formatTime(time){
let minute = Math.floor(time/60);
let second = Math.floor(time%60);
minute = minute<10?("0"+minute):minute;
second = second<10?("0"+second):second;
let res = minute+":"+second;
return res;
}
},
start:function(){
this.ctx.play();
this.setData({
isRunning:true
})
},
pause:function(){
this.ctx.pause();
this.setData({
isRunning:false
})
},
change:function(e){
let position = Math.floor(this.ctx.duration*e.detail.value/100);
this.ctx.seek(position);
},
mute:function(){
this.setData({
isMute:true
},() => {
this.ctx.volume = 0;
})
},
speak:function(){
this.setData({
isMute:false
},() => {
this.ctx.volume = 1;
})
}
})