一、项目展示
主页:
播放页:
搜索页:
排行榜页:
小控件:
二、项目结构
三、项目功能点
后端接口,使用node写的,使用了网易云音乐API:
封装的api文件
//env是基础地址js文件
import config from './env'
export default (url,method="GET",data={})=>{
return new Promise((resolve,reject)=>{
wx.request({
url: config.dev.baseUrl + url,
method,
data,
success(res){
// console.log(res.data);
if(res.statusCode == 200){
resolve(res.data)
}else{
wx.showToast({
title: '请求失败,请联系管理员',
})
reject('请求失败,请联系管理员')
}
},
fail(error){
wx.showToast({
title: '请求失败,请联系管理员',
})
reject('请求失败,请联系管理员')
}
})
})
}
import request from './request'
module.exports = {
// 获取banner
getBanner:()=> request('/banner','get',{type:'2'}),
// 推荐歌单
getrecommendMusic:()=> request('/personalized?limit=6','get',),
// 排行榜
getTopMusic:(idx)=>request(`/top/list?idx=${idx}`,'get'),
// 歌曲详情
getMusicDetail:(ids)=>request(`/song/detail?ids=${ids}`),
// 歌曲音频路径
getMusicUrl:(id)=>request(`/song/url?id=${id}`,'POST'),
// 热搜数据 /search/hot/detail
getHotMusicData:()=>request('/search/hot/detail'),
// 搜索歌曲 /search
getSearchMusic:(keywords,limit)=>request(`/search?keywords=${keywords}&limit=${limit}`),
//搜索歌曲关键字 /search/default
getSearchDefault:()=>request('/search/default'),
// 登录 网易云真实账号密码
login:(phone,password)=>request(`/login/cellphone?phone=${phone}&password=${password}`)
}
主页面:
- banner,滑动菜单栏采用微信的API(
swiper
与scroll-view
)进行开发 - 滑动到底部重新获取后续的歌曲,使用onReachBottom周期函数来监听页面到达底部,歌曲使用
slice
函数进行分页操作。
this.setData({
topList:hotMusicList.playlist,
todayMusic:hotMusicList.playlist.tracks.slice(0,size*page)
})
- 点击歌曲,进入播放页,传参歌曲id
/ 获取歌曲详情
goMusicDetail(e){
let ids = e.currentTarget.dataset.id
wx.redirectTo({
url:`../play/play?ids=${ids}`
})
},
播放页:
- 进度条使用微信组件
slider
,value
表示现在进度(0—100)
<view class="progress">
<slider bindchange='sliderChange' activeColor='blue' block-size="12" value='{{ProValue}}' />
</view>
- 进度条value转换成0-100的数值(歌曲当前时间/歌曲总时长*100)
let value = (music.currentTime/music.duration)*100
- 歌曲播放当前时间与总时长格式转换00:00格式
// 转换时间格式,将秒转换成00:00格式
s_to_hs(s){
//计算分钟
//算法:将秒数除以60,然后下舍入,既得到分钟数
let h = Math.floor(s/60);
//计算秒
//算法:取得秒%60的余数,既得到秒数
s=Math.trunc(s%60);
//将变量转换为字符串
h+='';
s+='';
//如果只有一位数,前面增加一个0
h = (h.length==1)?'0'+h:h;
s = (s.length==1)?'0'+s:s;
return h+':'+s;
},
- 歌曲进度条随歌曲播放,实时滚动,使用定时器,每秒改变data的数值
timer(){
// 定时器
setTimeout(() => {
music.currentTime
music.onTimeUpdate(() => {
let startTime = this.s_to_hs(music.currentTime)
let endTime = this.s_to_hs(music.duration)
let value = (music.currentTime/music.duration)*100
this.setData({
PlayStartTime:startTime,
PlayEndTime:endTime,
ProValue:value
})
})
}, 1000)
},
- ios静音下可以播放音频
// ios静音模式下可以播放音频
wx.setInnerAudioOption({
obeyMuteSwitch: false,
success: function (e) {
console.log(e)
console.log('play success')
},
fail: function (e) {
console.log(e)
console.log('play fail')
}
- 播放音频,返回主页面通过按钮也可以控制播放与暂停,将音频实例Music挂载到APP上面
music(){
music = wx.createInnerAudioContext();
if (wx.setInnerAudioOption) {
wx.setInnerAudioOption({
obeyMuteSwitch: false,
autoplay: true
})
}else {
music.obeyMuteSwitch = false;
music.autoplay = true;
}
music.src = this.data.musicUrl.url;
app.music = music
music.onPlay(()=>{
console.log('音乐播放');
this.setData({
isPlay:true
})
})
music.onStop(()=>{
console.log('音乐停止');
})
music.onPause(()=>{
console.log('音乐暂停');
this.setData({
isPlay:false
})
})
music.onError((res)=>{
console.log(music);
console.log(res.errMsg);
console.log(res.errCode);
})
music.onWaiting(()=>{
console.log('音频加载中...');
})
},
挂载APP实例上面,通过
app.music = music
app.music.play();//播放
app.music.pause();//暂停
- 拖动进度条,拖动slider后获取当前
value
,反向转换成秒数,将music.currentTime
修改成当前值
// 拖动进度条
sliderChange(e){
let val = e.detail.value
// console.log(music.duration);
let second = music.duration * val/100
this.setData({
PlayStartTime: this.s_to_hs(second)
})
music.currentTime = second;
this.timer();
},
- 播放音频封面图片旋转,暂停音乐停止旋转,使用了
animation-play-state
动画属性,使用监听音频函数
music.onPlay
与music.onPause
来检测播放与暂停,改变animation-play-state
的paused
与running
的值
<view class="imgUrl">
<image src="{{picUrl}}" mode="" class="{{isPlay? 'rotateImg':''}}" style="animation-play-state:paused" />
</view>
.imgUrl image{
width: 88%;
height: 88%;
border-radius: 50%;
align-self: center;
animation: rotateImg 10s linear infinite;
}
.rotateImg{
animation-play-state:running !important
}
@keyframes rotateImg {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
搜索页:
- 热门信息获取,
wx:for
循环遍历,搜索输入歌曲名回车之后,wx:if
隐藏热门信息,展示歌曲列表
<view class="hotMusicData" wx:if="{{isShow}}">
<text>热搜榜</text>
<view class="hotMusic" wx:for="{{hotMusicData}}" wx:for-index="hotIndex" wx:key="key">
<text class="hotIndex">{{hotIndex+1}}</text>
<view class="hotMusic_content">
<text>{{item.searchWord}}\n</text>
<text>{{item.content}}</text>
</view>
<text>{{item.score}}</text>
</view>
</view>
排行榜
排行榜滑块使用微信组件scroll-view
四、项目难处
项目初期看到尚硅谷的网易云微信小程序的项目,拿到了node的api后端接口,查看微信开发者文档,参考网易云音乐的页面写完了静态页面,封装api接口,统一管理所有api接口地址
退出播放页面返回主页面,下面出现播放暂停小控件,也能够控制音乐播放与暂停
,之前思路是跟vue一样使用插槽slot,但是后面实现起来各种bug,后面换的思路是让music
的音频实例让所有组件能够看到,想到了APP跟组件,直接挂载到app
上面,来控制音频的播放与暂停。- 播放页面进度条,播放暂停,时间显示功能,在进度条选择上面最开始选择的是
progress
组件,不过使用定时器不断改变value值,进度条progress
会反复从开头滑动,最后选择了slider
; - 每次通过点击音乐进入播放页面需要销毁上一个music实例,不然会同时播放几首歌曲,不过销毁实例时候需要判断是不是通过点击歌曲list进来的,通过主页面小控件进入的不会停止音乐。
五、项目不足
初次学习写微信小程序,很多东西写的很乱,差哪些页面就去写哪些页面,项目初期没有完整的规划,项目结构也不清晰,功能点也是按照网易云现有功能有啥就写啥,js的一些代码冗余性有点高,通用函数没有做到封装,整体看起来就是有点乱,一些功能点没有写出来,就只是还原的播放器的部分功能,以后还要多多学习。
六、项目地址
网易云微信小程序
https://gitee.com/yuan_henry/wechat-app