此设计界面比较简陋,请大家海涵。针对初学者的布局与js的结合用法
一、项目效果图:
(1)音乐播放页面
(2)播放器页面
(3)播放列表
(4)文件的创建
二、WXML的标签运用
(1)标签内容
1.运用到了view、swiper(滑块视图容器)、swiper-item、include(跳转到自己的页面)、image(放置图片)、block(占位符)、slider(滑动选择)、scroll-view(可滚动视图区域)等标签。理解所涉及标签的方法和属性。
(2)代码区域
1.index.wxml
<!-- 上导航部分 -->
<view class="tab">
<view class="tab-item {{tab==0?'active':''}}" bindtap="changeitem" data-item="0">音乐播放</view>
<view class="tab-item {{tab==1?'active':''}}" bindtap="changeitem" data-item="1">播放器</view>
<view class="tab-item {{tab==2?'active':''}}" bindtap="changeitem" data-item="2">播放列表</view>
</view>
<!-- 内容 -->
<view class="content">
<!-- 滑块视图容器 current当前所在滑块的 index-->
<swiper current="{{item}}" bindchange="changetab">
<swiper-item>
<!-- 跳转当前自己的文件 -->
<include src="info.wxml"></include>
</swiper-item>
<swiper-item>
<include src="play.wxml"></include>
</swiper-item>
<swiper-item>
<include src="playlist.wxml"></include>
</swiper-item>
</swiper>
</view>
<!-- 音乐导航底部 -->
<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="http://localhost:3000/images/16.png" bindtap="changePage" data-page="2" />
<!-- 播放或暂停 -->
<image wx:if="{{state=='paused'}}" src="http://localhost:3000/images/17.png" bindtap="play" />
<image wx:else src="http://localhost:3000/images/19.png" bindtap="pause" />
<!-- 下一曲 -->
<image src="http://localhost:3000/images/18.png" bindtap="next" />
</view>
</view>
2.info.wxml
<swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
<block wx:for="{{imgUrls}}" wx:key="unique">
<swiper-item>
<image src="{{item}}" class="slide-imge" style="width: 100%;"></image>
</swiper-item>
</block>
</swiper>
<view class="content-info-portal">
<view>
<image src="http://localhost:3000/images/22.png"></image>
<text>私人FM</text>
</view>
<view>
<image src="http://localhost:3000/images/20.png"></image>
<text>每日歌曲推荐</text>
</view>
<view>
<image src="http://localhost:3000/images/21.png"></image>
<text>云音乐新歌榜</text>
</view>
</view>
<view class="content-info-list">
<view class="list-title">推荐歌曲</view>
<view class="list-inner">
<view class="list-item">
<image src="http://localhost:3000/images/05.png"></image><view>流行--歌曲</view>
</view>
<view class="list-item">
<image src="http://localhost:3000/images/06.png"></image><view>经典--歌曲</view>
</view>
<view class="list-item">
<image src="http://localhost:3000/images/07.png"></image><view>民谣--歌曲</view>
</view>
<view class="list-item">
<image src="http://localhost:3000/images/08.png"></image><view>火爆--歌曲</view>
</view>
<view class="list-item">
<image src="http://localhost:3000/images/09.png"></image><view>翻唱--歌曲</view>
</view>
<view class="list-item">
<image src="http://localhost:3000/images/10.png"></image><view>温情--歌曲</view>
</view>
</view>
</view>
3.play.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.coverImgeUrl}}" style="animation-play-state: {{stata}};"></image>
</view>
<view class="content-play-progress"></view>
<!-- 播放进度和时间 -->
<view class="content-play-progress">
<text>{{play.currentTime}}</text>
<view>
<!-- 滑动选择器 -->
<slider bindtap="sliderChange" activeColor="#d33a31" block-size="12" backgroundColor="#dadada" value="{{play.percent}}"></slider>
</view>
<text>{{play.duration}}</text>
</view>
</view>
4.playlist.wxml
<scroll-view class="content-playlist" scroll-y>
<view class="playlist-item" wx:for="{{playlist}}" wx:key="id" bindtap="change" data-index="{{index}}">
<image class="playlist-cover" src="{{item.coverImgeUrl}}" />
<view class="playlist-info">
<view class="playlist-info-title">{{item.title}}</view>
<view class="playlist-info-singer">{{item.singer}}</view>
</view>
<view class="playlist-controls">
<text wx:if="{{index==playIndex}}">正在播放</text>
</view>
</view>
</scroll-view>
三、WXSS的运用
(1)需要注意样式设置
- display: flex;-----弹性盒子:水平的主轴(main axis)和垂直的交叉轴(cross axis)
- flex-direction:[row\column]-----代表排列方向, 决定主轴的方向:
flex-direction:row // 表示从左到右排列
flex-direction:row-reverse // 表示从右到左排列
flex-direction:column //表示从上到下排列
flex-direction:column-reverse //表示从下到上排列 - flex-wrap:wrap;-----换行后,使其间距相等
- justify-content: space-around;-----让排布均匀分布
- animation: musicStart 0.2s linear forwards;-----动画对象:让其以0.2秒的速度匀速动画
- @keyframes ------创建动画
(2)代码区域
page{
display: flex;
flex-direction: column;
background: #141b10;
color: #ccc;
height: 100%;
}
.tab{
/* r让他变成伸缩盒子 */
display: flex;
}
.tab-item{
flex: 1;
font-size: 10pt;
text-align: center;
line-height: 72rpx;
height: 72rpx;
border-bottom: 6rpx solid #eee;
}
/* 激活当前选项 */
.tab-item.active{
color: #c25b5b;
border-bottom-color:#c25b5b;
}
.content{
flex: 1;
}
.content > swiper{
/* 宽度给其自适应 */
height: 100%;
}
.player{
background: #222;
border-top: 2rpx solid #252525;
height: 112rpx;
}
.slide-image{
width: 100%;
height: 100%;
}
.content-slide-imge{
height: 30rpx;
margin-bottom: auto;
}
.content-info-portal{
display: flex;
margin-bottom: 15px;
}
.content-info-portal > view{
flex: 1;
font-size: 11pt;
text-align: center;
}
.content-info-portal image{
width: 120rpx;
height: 120rpx;
display: block;
margin: 20rpx auto;
}
.content-info-list{
font-size: 11pt;
margin-bottom: 20rpx;
}
.content-info-list > .list-title{
margin: 20rpx 35rpx;
}
.content-info-list > .list-inner{
display: flex;
flex-wrap: wrap;
margin: 0 20rpx;
}
.content-info-list > .list-inner > .list-item{
flex: 1;
}
.content-info-list > .list-inner > .list-item > image{
display: block;
width: 200rpx;
height: 200rpx;
margin: 0 auto;
border-radius: 10rpx;
border: 1rpx solid #555;
}
.content-info-list > .list-inner > .list-item > view{
width: 200rpx;
margin: 10rpx auto;
font-size: 10pt;
}
/* 音乐导航底部 */
.player {
display: flex;
align-items: center;
background: #222;
border-top: 1px solid #252525;
height: 112rpx;
}
.player-cover {
width: 100rpx;
height: 100rpx;
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-singer {
color: #888;
}
.player-controls image {
width: 80rpx;
height: 80rpx;
margin-right: 15rpx;
}
/* 播放器页面样式 */
.content-play{
display: flex;
/* 让排布均匀分布 */
justify-content: space-around;
/* 决定主轴,从上到下排列 还有一个从左到右row,相反则加-reverse*/
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;
}
/* 页面结构 */
.playlist-item{
display: flex;
align-items: center;
border-bottom: 1rpx solid #333;
height: 112rpx;
}
.playlist-cover{
width: 80rpx;
height: 80rpx;
margin-left: 15rpx;
border-radius: 8rpx;
border: 1px solid #333;
}
.playlist-info{
float: 1px;
font-size: 10pt;
line-height: 38rpx;
margin-left: 20rpx;
padding-bottom: 8rpx;
}
.playlist-info-singer{
color: #888;
}
.playlist-controls{
font-size: 10pt;
margin-right: 20rpx;
color: #c25b5b;
}
/* 播放和暂停的效果 */
.player-play > image:first-child{
animation-play-state: running;
}
.player-play > image:last-child{
animation: musicStart 0.2s linear forwards;
}
.player-pause > image:first-child{
animation-play-state: paused;
}
.player-pause > image:last-child{
animation: musicStop 0.2s linear forwards;
}
@keyframes musicStart{
from{transform: rotate(0deg);}
to{transform: rotate(20deg);}
}
@keyframes musicStop{
from{transform: rotate(20deg);}
to{transform: rotate(0deg);}
}
四、JS的运用
(1)需要注意js的语句设置
- 变量的初始化:
data:{
变量:值
}
- 数组的创建:
数组名称:[…]
- 绑定事件的创建:
绑定设置的名称:function(){ 方法 }
- 获取绑定事件的索引的方法:
绑定设置的名称:function(){
this.setData({ console.log(); })
}
(2)代码区域
// index.js
// 获取应用实例
const app = getApp()
Page({
data:{
item:0,
tab:0,
isPlayingMusic:false,
playlist:[
{
id:0,title:'钢琴曲',singer:'肖邦',src:'http://localhost:3000/images/song.mp3',coverImgeUrl:'http://localhost:3000/images/11.png'
},
{
id:1,title:'奏鸣曲',singer:'莫扎特',src:'http://localhost:3000/images/song.mp3',coverImgeUrl:'http://localhost:3000/images/12.png'
},
{
id:2,title:'欢乐颂',singer:'贝多芬',src:'http://localhost:3000/images/song.mp3',coverImgeUrl:'http://localhost:3000/images/13.png'
},
{
id:3,title:'爱之梦',singer:'李斯特',src:'http://localhost:3000/images/song.mp3',coverImgeUrl:'http://localhost:3000/images/14.png'
},
],
stata:'paused',
playIndex:0,
play:{
currentTime:'00:00',
duration:'00:00',
percent: 0,
title:'',
singer:'',
coverImgeUrl:'http://localhost:3000/images/11.png',
},
imgUrls:[
"http://localhost:3000/images/01.png",
"http://localhost:3000/images/02.png",
"http://localhost:3000/images/03.png",
"http://localhost:3000/images/04.png"
],
indicatorDots:true,
autoplay:true,
interval:3000,
duration:500,
},
changeitem(e){
// 获取点击的索引数据
this.setData({
// 给这个item赋值
item:e.target.dataset.item
})
},
changetab(e){
this.setData({tab:e.detail.current})
},
audioCtx:null,
onReady:function(){
// 音乐接口
this.audioCtx = wx.createInnerAudioContext()
//调用
this.setMusic(0)
},
setMusic(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.coverImgeUrl,
'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(){
// 如果满足,就等于0,不满足就加一
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()
}else{
this.pause()
}
},
//点击下一曲
changer:function(e){
this.setMusic(e.Target.dataset.index)
this.play()
},
onReady:function(){
this.audioCtx = wx.createInnerAudioContext()
var that = this
// 播放失败检测
this.audioCtx.onError(function(){
console.log('播放失败:'+ that.audioCtx.src)
})
// 播放完成自动换下一曲
this.audioCtx.onEnded(function(){
thta.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
})
})
// 默认选择第一曲
this.setMusic(0)
// 格式化时间
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)
}
},
//进度条到哪,就播放到哪
sliderChange: function(e){
var second = e.detail.value * this.audioCtx.duration / 100
this.audioCtx.seek(second)
},
sliderChanging:function(e){
console.log(e.detail.value)
},
})
五、音频和图片的导入
(1)node的方法用服务端进行导入
1.如果还不会用node的同学,可以跟一下以下教程:
下载地址与教程:https://nodejs.org/en/download/