文章目录
前情提要
每个小程序都需要在App.js
中调用 App({})
注册小程序实例。
App({
globalData:{
isPlayGlobal:false,
musicIdGlobal:''
}
})
整个小程序只有一个App实例,是全部页面共享的。可以通过 getApp()
获取到全局唯一的App实例,获得App上的数据或函数。
const appInstance = getApp();
const {isPlayGlobal,musicIdGlobal} = appInstance.globalData;
搭建静态资源服务器
- 全局安装serve:
npm install -g serve
- 在任何你想的地方新建文件夹:
resources
。resources下新建文件夹:images
,用于存放静态图片资源;resources下新建文件夹:videos
,用于存放视频文件;resources下新建文件夹:audios
,用于存放音频文件。 - 启动服务器:
serve resources
。
小程序项目
代码涉及的主要文件有:
- app.json
- app.js
- app.wxss
- pages/index/index.json
- pages/index/index.wxml
- pages/index/index.wxss
- pages/index/index.js
- pages/music/music.json
- pages/music/music.wxml
- pages/music/music.wxss
- pages/music/music.js
app.json
{
"pages": [
"pages/index/index",
"pages/music/music"
],
"window": {
"navigationBarBackgroundColor": "#624d2e",
"navigationBarTitleText": "首页",
"navigationBarTextStyle": "white"
},
"requiredBackgroundModes": [
"audio"
],
"style": "v2",
"sitemapLocation": "sitemap.json"
}
app.js
App({
globalData:{
isPlayGlobal:false, //当前是否有歌曲在播放
musicIdGlobal:'' //当前正在播放的歌曲是哪首
}
})
app.wxss
page{
height: 100%;
}
pages/index/index.json
{
"usingComponents": {},
"navigationBarTitleText": "播放列表"
}
pages/index/index.wxml
<view class="index-container">
<view class="header">
<image src="/static/images/icon-play-square.png"></image>
<text>播放全部</text>
<text>{{musicList.length}}</text>
</view>
<scroll-view class="music-list" enable-flex scroll-y >
<view class="music-item" wx:for="{{musicList}}" wx:key="id" bindtap="handleTap" data-musicitem="{{item}}">
<view class="music-index">{{index+1}}</view>
<image class="music-image" src="{{item.picUrl}}"></image>
<view class="music-info">
<view class="musci-name">{{item.name}}</view>
<view class="music-author">{{item.author}}</view>
</view>
<image class="btn-more" src="/static/images/icon-more.png"></image>
</view>
</scroll-view>
</view>
pages/index/index.wxss
.index-container{
padding: 20rpx;
background:#624d2e
}
.header{
display: flex;
align-items: center;
}
.header image{
width: 28rpx;
height: 28rpx;
margin-right: 20rpx;
}
.header text{
color: #fff;
height: 28rpx;
line-height: 28rpx;
margin-right: 20rpx;
font-size: 28rpx;
}
.music-list{
margin-top: 20rpx;
color: #fff;
height: calc(100vh - 88rpx);
}
.music-item{
display: flex;
align-items: center;
height: 100rpx;
margin: 20rpx 0;
position: relative;
}
.music-item .music-index{
width: 50rpx;
font-size: 28rpx;
color: #aaa;
}
.music-item .music-image{
width: 80rpx;
height: 80rpx;
border-radius: 6rpx;
margin-right: 20rpx;
}
.music-item .music-info{
display: flex;
flex-direction: column;
}
.music-item .music-info .music-author{
font-size: 24rpx;
color: #aaa;
margin-top: 10rpx;
}
.music-item .btn-more{
width: 36rpx;
height: 36rpx;
position: absolute;
right: 0;
}
pages/index/index.js
const host = "http://localhost:3000"
Page({
data:{
musicList:[]
},
onLoad(){
this.getDataFromServer();
},
getDataFromServer(){
const result = [
{id:"001",name:"滂沱大雨里","author":"李若溪","picUrl":host+"/images/滂沱大雨里.jpg","url":host+"/audios/滂沱大雨里.mp3"},
{id:"002",name:"快乐的小青蛙","author":"刘士鸣","picUrl":host+"/images/快乐的小青蛙.jpg","url":host+"/audios/快乐的小青蛙.mp3"},
{id:"003",name:"国王与乞丐","author":"华晨宇","picUrl":host+"/images/国王与乞丐.jpg","url":host+"/audios/国王与乞丐.mp3"},
{id:"004",name:"奇洛李维斯回信","author":"薛凯琪","picUrl":host+"/images/奇洛李维斯回信.jpg","url":host+"/audios/奇洛李维斯回信.mp3"},
{id:"005",name:"红日","author":"李克勤","picUrl":host+"/images/红日.jpg","url":host+"/audios/红日.mp3"},
{id:"006",name:"快乐崇拜","author":"潘玮柏 张韶涵","picUrl":host+"/images/快乐崇拜.jpg","url":host+"/audios/快乐崇拜.mp3"},
{id:"007",name:"门没锁","author":"黄品冠","picUrl":host+"/images/门没锁.jpg","url":host+"/audios/门没锁.mp3"},
{id:"008",name:"就是爱你","author":"陶喆","picUrl":host+"/images/就是爱你.jpg","url":host+"/audios/就是爱你.mp3"},
{id:"009",name:"火力全开","author":"王力宏","picUrl":host+"/images/火力全开.jpg","url":host+"/audios/火力全开.mp3"},
{id:"0010",name:"友情岁月","author":"陈小春 郑伊健 谢天华 林晓峰 钱嘉乐","picUrl":host+"/images/友情岁月.jpg","url":host+"/audios/友情岁月.mp3"},
{id:"0011",name:"温柔","author":"五月天","picUrl":host+"/images/温柔.jpg","url":host+"/audios/温柔.mp3"}
];
this.setData({musicList:result});
},
handleTap(event){
const {musicitem} = event.currentTarget.dataset;
wx.navigateTo({
url: '/pages/music/music?musicitem='+JSON.stringify(musicitem),
})
}
})
pages/music/music.json
{
"usingComponents": {},
"navigationBarBackgroundColor": "#2f434e",
"navigationBarTitleText": "音乐详情"
}
pages/music/music.wxml
<view class="music-container">
<view class="music-name">{{music.name}}</view>
<view class="music-author">{{music.author}}</view>
<image class="arm {{isPlay&&'arm-reset'}}" src="/static/images/arm.png"></image>
<view class="disc-container {{isPlay&&'disc-animate'}}">
<image class="disc" src="/static/images/disc.png"></image>
<image class="music-image" src="{{music.picUrl}}"></image>
</view>
<view class="player">
<view class="btns">
<image class="loop-btn" src="/static/images/loop.png"></image>
<image class="prev-btn" src="/static/images/prev.png"></image>
<image class="play-btn" src="{{isPlay?'/static/images/stop.png':'/static/images/play.png'}}" bindtap="handlePlay"></image>
<image class="next-btn" src="/static/images/next.png"></image>
<image class="list-btn" src="/static/images/list.png"></image>
</view>
</view>
</view>
pages/music/music.wxss
.music-container{
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
background: #2f434e;
position: relative;
}
.music-container .music-name{
margin: 10rpx 0;
color: #fff;
font-size: 36rpx;
}
.music-container .music-author{
color: #bbb;
font-size: 28rpx;
margin: 6rpx 0;
}
.music-container .arm{
width:204rpx;
height: 358rpx;
position: relative;
left: 72rpx;
z-index: 99;
transform: rotate(-15deg);
transform-origin: 30rpx 30rpx;
transition: transform .7s linear;
}
.disc-container{
position: relative;
top: -128rpx;
width: 490rpx;
height: 490rpx;
}
.disc-container .disc{
width: 100%;
height: 100%;
}
.disc-container .music-image{
width: 270rpx;
height: 270rpx;
border-radius: 100%;
position: absolute;
left: 0;right: 0;top: 0;bottom: 0;
margin: auto;
}
.music-container .arm-reset{
transform: rotate(0deg);
}
.disc-animate{
animation: rotate 2.5s 1s linear infinite;
}
@keyframes rotate{
from{
transform: rotate(0deg);
}
to{
transform: rotate(360deg);
}
}
.player{
width: 100%;
position: absolute;
bottom: 60rpx;
}
.btns{
display: flex;
align-items: center;
justify-content: space-evenly;
}
.btns image{
width: 36rpx;
height: 36rpx;
}
.btns .play-btn,.btns .stop-btn{
width: 90rpx;
height: 90rpx;
}
pages/music/music.js
const appInstance = getApp();
Page({
data:{
isPlay:false,
music:{}
},
onLoad(options){
const music = JSON.parse(options.musicitem);
this.setData({music})
// wx.setNavigationBarTitle({
// title: music.name,
// })
const {isPlayGlobal,musicIdGlobal} = appInstance.globalData;
const {id} = this.data.music;
if(isPlayGlobal && musicIdGlobal === id) {
this.setData({isPlay:true});
}
this.bam = wx.getBackgroundAudioManager();
this.bam.onPlay(() => {
this.setData({isPlay:true})
appInstance.globalData.isPlayGlobal = true;
appInstance.globalData.musicIdGlobal = this.data.music.id;
})
this.bam.onPause(() => {
this.setData({isPlay:false})
appInstance.globalData.isPlayGlobal = false;
})
this.bam.onStop(() => {
this.setData({isPlay:false})
appInstance.globalData.isPlayGlobal = false;
})
this.bam.onEnded(() => {
this.setData({isPlay:false});
appInstance.globalData.isPlayGlobal = false;
})
},
handlePlay(){
const isPlay = !this.data.isPlay;
this.setData({isPlay});
this.musicControl();
},
musicControl(){
const {isPlay} = this.data;
if(isPlay){
this.bam.src = this.data.music.url;
this.bam.title = this.data.music.name;
}else{
this.bam.pause();
}
}
})