"音乐"小程序:播放器
来自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) },
效果:
定义基础数据
在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; }
- border-radius: 50%; 将盒子形状设置为圆形
- animation: rotateImage 10s linear infinite; 实现动画效果
- @keyframes 设置动画:https://www.runoob.com/cssref/css3-pr-animation-keyframes.html
效果图
实现音乐播放功能
音乐播放功能 主要创建一个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; }
效果图:
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) },
效果:
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) },