Repository: mySkey/music-small
Branch: master
Commit: a21a9238173a
Files: 42
Total size: 51.7 KB
Directory structure:
gitextract_ec2v8ip_/
├── README.md
├── app.js
├── app.json
├── app.wxss
├── components/
│ ├── controls.js
│ ├── controls.json
│ ├── controls.wxml
│ ├── controls.wxss
│ ├── loadmore.js
│ ├── loadmore.json
│ ├── loadmore.wxml
│ ├── loadmore.wxss
│ ├── lrc.js
│ ├── lrc.json
│ ├── lrc.wxml
│ ├── lrc.wxss
│ ├── player.js
│ ├── player.json
│ ├── player.wxml
│ ├── player.wxss
│ ├── progress.js
│ ├── progress.json
│ ├── progress.wxml
│ └── progress.wxss
├── pages/
│ └── music/
│ ├── detail.js
│ ├── detail.json
│ ├── detail.wxml
│ ├── detail.wxss
│ ├── list.js
│ ├── list.json
│ ├── list.wxml
│ └── list.wxss
├── project.config.json
└── utils/
├── js/
│ ├── ajax.js
│ ├── audio.js
│ ├── common.js
│ ├── dayjs.js
│ └── props.js
├── wxs/
│ └── time.wxs
└── wxss/
├── icon.wxss
├── reset.wxss
└── style.wxss
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
### 扫码预览

### 一、需求分析
* 基本功能
上一曲、下一曲、播放、暂停、列表播放
* 切换到别的页面播放继续
* 歌词同步
1、歌词随音乐进度更新
2、拖动歌词后出现可调节位置的控件,此时歌词滚动暂停
3、点击控件播放,关闭控件,改变进度
4、不点击,5s后关闭控件
* 进度条播放
可点击或者拖动进度条来改变歌曲进度
* 播放模式
单曲、列表、随机三种播放模式
* 倍速
可在不同倍速下播放,并且不同倍速下歌词同步
### 其中的经验:
* 1、wxs支持es4的语法
* 2、在app.json中设置"requiredBackgroundModes": ["audio"],将开启后台播放
* 3、wx.getBackgroundAudioManager()的onEnded监听在安卓机上面不生效
* 4、不支持倍速
================================================
FILE: app.js
================================================
//app.js
App({
onLaunch: function () {
wx.setNavigationBarTitle({
title: 'mySkey音乐'
})
this.initAudio()
},
onShow(){
if(this.audioDom.paused){
this.player.status = 2;
}
},
onHide: function () {
},
player: {
list: [],
current_music: 0,
mode: 0, // 0 单曲 1 顺序 2 随机
status: 0, // 0 未播放 1 播放 2 暂停中 3 已结束
playbackRate: 1, // 倍速
a_resource: '',
i_resource: '',
global_show: 0, // 全局显示 0 不显示 1 显示
playing: {
id: '',
name: '',
cover: '',
url: '',
singer: {
avatar: '',
name: ''
},
currentTime: 0,
duration: 0,
timeArr: [],
lrcArr: []
}
},
audioDom: wx.getBackgroundAudioManager(),
initAudio(){
this.audioDom.title = '起风了';
this.audioDom.epname = '555';
this.audioDom.singer = 'mySkey';
this.audioDom.coverImgUrl = 'http://img.22family.com/mySKey/favicon.ico';
this.audioDom.paused = true;
this.audioDom.stop = true;
}
})
================================================
FILE: app.json
================================================
{
"pages": [
"pages/music/list",
"pages/music/detail"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "black"
},
"requiredBackgroundModes": ["audio"]
}
================================================
FILE: app.wxss
================================================
/**app.wxss**/
@import './utils/wxss/reset.wxss';
@import './utils/wxss/icon.wxss';
@import './utils/wxss/style.wxss';
.container {
height: 100%;
box-sizing: border-box;
}
================================================
FILE: components/controls.js
================================================
// components/controls.js
const app = getApp()
import props from '../utils/js/props.js'
import common from '../utils/js/common.js'
Component({
/**
* 组件的属性列表
*/
properties: {
currentTime: {
type: Number,
value: 0,
observer: function (newVal, oldVal, changedPath) {
props.setPlaying.call(this, { currentTime: newVal, duration: app.audioDom.duration })
//props.setPlayer.call(this, { status: app.player.status })
}
}
},
/**
* 组件的初始数据
*/
data: {
player:{},
},
attached(){
props.setPlayer.call(this, app.player)
},
/**
* 组件的方法列表
*/
methods: {
pauseAudio() {
app.audioDom.pause()
props.setPlayer.call(this, { status: 2 })
},
palyAudio() {
app.audioDom.play()
props.setPlayer.call(this, { status: 1 })
},
playLast() {
if (this.data.player.list.length > 0) {
this.triggerEvent('playLast')
}
},
playNext() {
if (this.data.player.list.length > 0) {
this.triggerEvent('playNext')
}
},
changeMode() {
let mode = this.data.player.mode + 1
if (mode > 2) {
mode = 0
}
props.setPlayer.call(this, { mode })
},
changeRate() {
common.toast('小程序不支持倍速功能!')
return
let playbackRate = this.data.player.playbackRate + 0.25
if (playbackRate > 2) playbackRate = 0.5
props.setPlayer(this, { playbackRate })
global.audioDom.playbackRate = playbackRate;
},
progressTouch() {
this.setState({ userChange: true })
},
changeProgress(radio) {
let currentTime = Math.floor(radio * this.props.audio.duration)
global.audioDom.currentTime = currentTime
this.props.setCurrentTime(currentTime)
this.setState({ userChange: false })
}
}
})
================================================
FILE: components/controls.json
================================================
{
"component": true,
"usingComponents": {
"myProgress": "/components/progress"
}
}
================================================
FILE: components/controls.wxml
================================================
{{time.getAudioTime(player.playing.currentTime)}}
{{time.getAudioTime(player.playing.duration)}}
正常
×{{player.playbackRate}}
================================================
FILE: components/controls.wxss
================================================
/* components/controls.wxss */
@import '/utils/wxss/style.wxss';
@import '/utils/wxss/icon.wxss';
.controls{
width: 100%;
position: absolute;
bottom: 2rem;
left: 0;
}
.controls .time{
color: #fff;
font-size: 0.6rem;
align-items: center;
}
.controls .time .progress{
width: 10rem;
margin: 0 16px;
}
.controls .btns{
align-items: center;
color: #dd5866;
}
.controls .btns .play_btn{
align-items: center;
margin: 0 2rem;
}
.controls .btns .last_next{
font-size: 1.2rem;
}
.controls .btns .play_pause{
font-size: 2.4rem;
margin: 0 1rem;
}
.controls .btns .mode_rete{
align-items: center;
font-size: 0.7rem;
color: #fff;
min-width: 40px;
}
.controls .btns .mode_rete .mode{
font-size: 1rem;
}
================================================
FILE: components/loadmore.js
================================================
// components/loadmore.js
Component({
/**
* 组件的属性列表
*/
properties: {
loading: {
type: Number,
value: 0,
observer: function (newVal, oldVal, changedPath) {
this.setData({ _loading: newVal });
}
}
},
/**
* 组件的初始数据
*/
data: {
_loading: 0
},
/**
* 组件的方法列表
*/
methods: {
}
})
================================================
FILE: components/loadmore.json
================================================
{
"component": true,
"usingComponents": {}
}
================================================
FILE: components/loadmore.wxml
================================================
已加载全部
================================================
FILE: components/loadmore.wxss
================================================
/* components/loadmore.wxss */
.wrap{padding:20rpx 0 50rpx 0;}
.loading-dot{
width:100%; height:40rpx; overflow:hidden; display:flex;
align-items:center; justify-content:center;
}
.loading-dot .dot{
display:inline-block; width:16rpx; height:16rpx; border-radius:50%; overflow: hidden;
background:#f2f2f2; margin:0 10rpx;
-webkit-animation: bouncedelay 1s infinite ease-in-out;
animation: bouncedelay 1s infinite ease-in-out;
-webkit-animation-fill-mode: both;
animation-fill-mode: both
}
.loading-dot .dot-1 {-webkit-animation-delay: -.48s; animation-delay: -.48s}
.loading-dot .dot-2 {-webkit-animation-delay: -.24s; animation-delay: -.24s}
@keyframes bouncedelay {
0%,100%,80% {background:lightgray;}
40% {background:gray;}
}
/* @keyframes bouncedelay {
0%,100%,80% {transform: scale(0); -webkit-transform: scale(0)}
40% {transform: scale(1);-webkit-transform: scale(1)}
} */
.all{font-size:24rpx;color:#e8e8e8;text-align:center;}
.placeholder{font-size:24rpx;}
================================================
FILE: components/lrc.js
================================================
// components/lrc.js
const app = getApp()
import props from '../utils/js/props.js'
import common from '../utils/js/common.js'
Component({
/**
* 组件的属性列表
*/
properties: {
currentTime: {
type: Number,
value: 0,
observer: function (newVal, oldVal, changedPath) {
if (app.player.playing.lrcArr.length > 0){
props.setPlaying.call(this, { currentTime: newVal })
this.getCurrentLrc()
}
}
}
},
/**
* 组件的初始数据
*/
data: {
player:{},
currentLrc: 0,
currentWidth: 0,
listTop: 0,
useTime: 1,
userChange: false,
changeTo: 0
},
attached() {
//console.log(app.player)
this.setData({ player: app.player })
},
/**
* 组件的方法列表
*/
methods: {
getCurrentLrc() {
let player = app.player, audio = app.player.playing;
let { currentTime } = audio
let currentLrc = 0;
audio.timeArr.forEach((v, k) => {
if (currentTime > this.getSecond(v)) {
currentLrc = k
}
})
// 更新当前歌词
if (currentLrc !== this.data.currentLrc) {
this.setData({ currentLrc, currentWidth: 0 }, () => {
this.getCurrentWidth((currentWidth)=>{
if (currentLrc < audio.timeArr.length - 1) {
let useTime = this.getSecond(audio.timeArr[currentLrc + 1]) - this.getSecond(audio.timeArr[currentLrc])
// 根据当前的倍速来决定时间
useTime = useTime / player.playbackRate
if (useTime > 10) {
this.setData({ useTime: 10 })
return
}
this.setData({ useTime, currentWidth })
}
})
})
if (!this.data.userChange) {
this.scrollLrc(currentLrc)
}
} else {
this.getCurrentWidth((currentWidth)=>{
this.setData({ currentWidth })
})
}
},
getCurrentWidth(cb){
let query = wx.createSelectorQuery().in(this)
query.select('.lrcItemShow').boundingClientRect(function (res) {
//console.log(res.width)
if(res){
cb && cb(res.width)
}
}).exec()
},
getSecond(t) {
let minute = Number(t.slice(0, 2))
let second = Number(t.slice(3, 5))
let minS = Number(t.slice(7))
return minS > 100 ? (minute * 60 + second + minS / 1000) : (minute * 60 + second + minS / 100)
},
// 歌词滚动
scrollLrc(currentLrc) {
if (currentLrc) {
let listTop = currentLrc * 32
this.setData({ listTop })
}
},
// 滑动歌词调整进度
handleMove() {
if(this.data.userChange){
let query = wx.createSelectorQuery().in(this)
query.select('.lrcList').boundingClientRect((res)=>{
//console.log(res.top / 32)
let currentLrc = (-Math.round(res.top / 32)) + 3
let time = app.player.playing.timeArr[currentLrc]
let currentTime = Math.ceil(common.getSecond(time))
this.setData({ changeTo: currentTime })
}).exec()
}
},
changeUserStatus(){
clearTimeout(this.timer)
this.setData({ userChange: true })
this.timer = setTimeout(() => {
this.setData({ userChange: false })
}, 5000)
},
changeToLrc() {
this.setData({ userChange: false }, () => {
wx.seekBackgroundAudio({
position: this.data.changeTo,
})
})
}
}
})
================================================
FILE: components/lrc.json
================================================
{
"component": true,
"usingComponents": {}
}
================================================
FILE: components/lrc.wxml
================================================
{{v}}
{{v}}
{{v}}
{{time.getAudioTime(changeTo)}}
================================================
FILE: components/lrc.wxss
================================================
/* components/lrc.wxss */
@import '/utils/wxss/style.wxss';
@import '/utils/wxss/icon.wxss';
.lrc_container{
position: absolute;
top: 80px;
left:0;
}
.lrcList{
width: 100vw;
text-align: center;
align-items: center;
padding-top: 160px; /* 从第6句开始特殊滑动 */
padding-bottom: 3rem;
}
.lrcList .lrcItem{
color: #fff;
height: 32px;
line-height: 32px;
position: relative;
white-space: nowrap;
}
.lrcList .lrcItemShow{
position: absolute;
color: #fff;
font-size: 1rem;
top:0;
left:0;
z-index: 98;
white-space: nowrap;
}
.lrcList .lrcItemShowIng{
position: absolute;
color: #dd5866;
font-size: 1rem;
top:0;
left:0;
z-index: 99;
white-space: nowrap;
overflow: hidden;
width: 0;
}
.swiper{
width: 100%;
height: 20px;
line-height: 20px;
padding: 0 1rem;
box-sizing: border-box;
position: absolute;
top: 166px; /* 从第六上面出现刻度线 */
left: 0;
align-items: center;
font-size: 28rpx;
color: #db3e4b
}
.swiper .line{
width: 70%;
height: 1px;
background: radial-gradient(at 50% 0, transparent, transparent, rgba(252, 231, 231, 0.7),rgba(252, 231, 231, 0.7));
}
.swiper .play .icon-play{
font-size: 40rpx;
}
================================================
FILE: components/player.js
================================================
// components/player.js
const app = getApp()
import props from '../utils/js/props.js'
Component({
/**
* 组件的属性列表
*/
properties: {
currentTime: {
type: Number,
value: 0,
observer: function (newVal, oldVal, changedPath) {
if (newVal>0) {
props.setPlayer.call(this, app.player)
}
}
}
},
/**
* 组件的初始数据
*/
data: {
player:{}
},
attached(){
},
/**
* 组件的方法列表
*/
methods: {
pauseAudio() {
app.audioDom.pause()
props.setPlayer.call(this, { status: 2 })
this.triggerEvent('updatePlayer')
},
playAudio() {
app.audioDom.play()
props.setPlayer.call(this, { status: 1 })
this.triggerEvent('updatePlayer')
},
playLast() {
let current_music = app.player.current_music - 1
if (current_music < 0) {
current_music = app.player.list.length - 1
}
this.playCurrent(current_music)
},
playNext() {
let current_music = app.player.current_music + 1
if (current_music >= app.player.list.length) {
current_music = 0
}
this.playCurrent(current_music)
},
playCurrent(current_music) {
props.setPlayer.call(this, { current_music, status: 1 })
props.setPlaying.call(this, app.player.list[current_music], ()=>{
let audioDom = app.audioDom
audioDom.title = app.player.playing.name
audioDom.src = app.player.a_resource + app.player.playing.url
audioDom.coverImgUrl = app.player.i_resource + app.player.playing.cover + '-ph'
audioDom.play()
})
this.triggerEvent('updatePlayer')
},
closePlayer() {
props.setPlayer.call(this, { global_show: 0 })
},
toDtail() {
let { id } = app.player.playing
let url = `/pages/music/detail?id=${id}`
wx.navigateTo({
url
})
}
}
})
================================================
FILE: components/player.json
================================================
{
"component": true,
"usingComponents": {}
}
================================================
FILE: components/player.wxml
================================================
{{player.playing.name}}
{{player.playing.singer.name}}
================================================
FILE: components/player.wxss
================================================
/* components/player.wxss */
@import '/utils/wxss/style.wxss';
@import '/utils/wxss/icon.wxss';
.player{
width: 90%;
padding: 0.2rem 0.5rem;
border-radius: 0.3rem;
box-sizing: border-box;
position: fixed;
z-index: 9999;
background: #999;
bottom: 4rem;
left:5%;
align-items: center;
}
.avatar{
width: 2rem;
height: 2rem;
border-radius: 50%;
overflow: hidden;
margin-right: 0.5rem;
}
.avatar_img{
width: 2rem;
height: 2rem;
border-radius: 50%;
}
.content{
color: #fff;
font-size: 0.7rem;
}
.content .singer{
margin-top: 0.2rem;
font-size: 0.6rem;
color: #d2d2d2;
}
.content .right{
align-items: center;
}
.content .right .controls{
align-items: center;
}
.content .right .controls .last_next{
font-size:1rem;
}
.content .right .controls .play_pause{
font-size: 1.7rem;
margin: 0 0.3rem;
}
.content .right .delete{
align-items: center;
margin-left: 1rem;
}
.content .right .delete .line{
height: 1.3rem;
width: 2px;
background: #fff;
margin-right: 0.5rem;
}
@keyframes rotateImg{
from{transform: rotate(0);}
to{transform: rotate(360deg);}
}
================================================
FILE: components/progress.js
================================================
// components/progress.js
const app = getApp()
import props from '../utils/js/props.js'
Component({
/**
* 组件的属性列表
*/
properties: {
currentTime: {
type: Number,
value: 0,
observer: function (newVal, oldVal, changedPath) {
props.setPlaying.call(this, { currentTime: newVal, duration: app.audioDom.duration })
if(!this.data.userChange){
this.updateProgress()
}
}
}
},
/**
* 组件的初始数据
*/
data: {
player:{},
left: 0,
sliderW: 14,
userChange: false,
swiperWidth: 0,
swiperLeft: 0,
},
ready() {
this.getSwiperInfo()
},
/**
* 组件的方法列表
*/
methods: {
getSwiperInfo(){
const that = this;
let query = wx.createSelectorQuery().in(this)
query.select('.swiper').boundingClientRect(function (res) {
//console.log(res)
that.setData({ swiperWidth: res.width, swiperLeft: res.left })
}).exec()
},
updateProgress(){
let { currentTime, duration } = app.player.playing;
let left = Math.floor(this.data.swiperWidth * (currentTime / duration))
this.setData({ left })
},
swiperTouch(e) {
let swiperWidth = this.data.swiperWidth
let startX = this.data.swiperLeft
let endX = e.touches[0].clientX
this.setData({ left: endX - startX })
let position = ((endX - startX) / swiperWidth) * app.audioDom.duration
wx.seekBackgroundAudio({
position: Math.round(position),
})
},
touchStart(e) {
this.setData({ sliderW: 18, userChange: true })
},
touchMove(e) {
let swiperWidth = this.data.swiperWidth
let sliderWidth = this.data.sliderW
let startX = this.data.swiperLeft
let endX = e.touches[0].clientX
if (endX - startX <= 0) {
this.setData({ left: 0 })
return
}
if (endX - startX >= (swiperWidth - sliderWidth)) {
this.setData({ left: swiperWidth - sliderWidth })
return
}
this.setData({ left: endX - startX })
},
touchEnd() {
let swiperWidth = this.data.swiperWidth
this.setData({ sliderW: 12, userChange: false })
//this.props.changeProgress(this.data.left / swiperWidth)
let position = (this.data.left / swiperWidth) * app.audioDom.duration
wx.seekBackgroundAudio({
position: Math.round(position),
})
}
}
})
================================================
FILE: components/progress.json
================================================
{
"component": true,
"usingComponents": {}
}
================================================
FILE: components/progress.wxml
================================================
================================================
FILE: components/progress.wxss
================================================
/* components/progress.wxss */
.swiper{
width: 100%;
height: 6px;
background: #d2d2d2;
margin: 20px 0;
position: relative;
border-radius: 6px;
}
.line{
height: 6px;
background: #dd5866;
position: absolute;
left: 0;
top: 0;
border-radius: 6px 0 0 6px;
}
.slider{
border-radius: 50%;
background: #33c9d4;
position: absolute;
}
================================================
FILE: pages/music/detail.js
================================================
// pages/music/detail.js
import props from '../../utils/js/props.js'
import common from '../../utils/js/common.js'
import ajax from '../../utils/js/ajax.js'
const app = getApp()
let audioDom = app.audioDom;
Page({
/**
* 页面的初始数据
*/
data: {
player:{},
id: '',
audioDom:''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
let id = options.id || 1
if (id == app.player.playing.id){
this.setData({ id }, ()=>{
this.updateLrc()
})
}else{
wx.stopBackgroundAudio()
this.setData({ id: options.id || 1 }, () => {
this.getDetail()
})
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
props.setPlayer.call(this, app.player)
this.audioWatch()
},
updeData(current_music){
if (current_music !== this.data.current_music) {
props.setPlayer.call(this, { current_music })
props.setPlaying.call(this, app.player.list[current_music], ()=>{
this.playAudio()
this.setData({ id: app.player.playing.id }, () => this.updateLrc())
})
}
},
getDetail() {
ajax.get('audio/detail', { id: this.data.id }).then(res => {
if (res.code === 0) {
let { a_resource, i_resource } = res.data;
let { lrc, id, url, cover, singer, name } = res.data.audio
let { timeArr, lrcArr } = common.analysis(lrc)
props.setPlaying.call(this, { id, timeArr, lrcArr, url, singer, name, cover })
props.setPlayer.call(this, { i_resource, a_resource, global_show: 1, status: 1 })
this.playAudio()
}
})
},
updateLrc() {
ajax.get('lrc', { id: this.data.id }).then(res => {
if (res.code === 0) {
let lrc = res.data.lrc
let { timeArr, lrcArr } = common.analysis(lrc)
props.setPlaying.call(this, { timeArr, lrcArr })
}
})
},
audioWatch(){
let audioDom = app.audioDom
audioDom.onPlay(() => {
props.setPlayer.call(this, { status: 1 })
props.setPlaying.call(this, { duration: audioDom })
})
audioDom.onPause(()=>{
props.setPlayer.call(this, { status: 2 })
})
audioDom.onTimeUpdate(() => {
props.setPlaying.call(this, { currentTime: audioDom.currentTime })
})
audioDom.onEnded(() => {
// 安卓监听不到。。。,并没有问题,是将接口使用错误了
this.audioEnded()
})
},
audioEnded(){
let player = app.player, playing = app.player.playing;
let mode = app.player.mode;
switch (mode) { // 0 单曲 1 顺序 2 随机
case 0:
console.log('单曲模式')
this.playAudio()
break;
case 1:
if (player.list.length > 0) {
console.log('列表模式下一曲')
let current_music = player.current_music + 1
if (current_music >= player.list.length) {
current_music = 0;
}
this.updeData(current_music)
return
}
app.audioDom.pause()
break;
case 2:
if (player.list.length > 0) {
console.log('随机模式下一曲')
let current_music = Math.floor(Math.random() * player.list.length)
this.updeData(current_music)
return
}
app.audioDom.pause()
break;
default:
app.audioDom.pause()
}
},
playAudio(){
let audioDom = app.audioDom
wx.setNavigationBarTitle({
title: app.player.playing.name
})
audioDom.title = app.player.playing.name
audioDom.src = app.player.a_resource + app.player.playing.url
audioDom.coverImgUrl = app.player.i_resource + app.player.playing.cover + '-ph'
audioDom.play()
},
playLast() {
let current_music = app.player.current_music - 1
if (current_music < 0) {
current_music = app.player.list.length - 1
}
props.setPlayer.call(this, { current_music })
this.setData({ current_music }, () => {
let id = app.player.list[current_music].id
this.setData({ id }, () => this.getDetail())
})
},
playNext() {
let current_music = app.player.current_music + 1
if (current_music >= app.player.list.length) {
current_music = 0
}
props.setPlayer.call(this, { current_music })
this.setData({ current_music }, () => {
let id = app.player.list[current_music].id
this.setData({ id }, () => this.getDetail())
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
================================================
FILE: pages/music/detail.json
================================================
{
"usingComponents": {
"lrc": "/components/lrc",
"controls": "/components/controls"
}
}
================================================
FILE: pages/music/detail.wxml
================================================
================================================
FILE: pages/music/detail.wxss
================================================
/* pages/music/detail.wxss */
.detail{
width: 100%;
height: 100vh;
overflow: hidden;
}
.detail_container{
width: 100%;
height: 100vh;
position: fixed;
top:0;
left: 0;
background: rgba(0,0,0,0.25);
}
================================================
FILE: pages/music/list.js
================================================
// pages/music/list.js
const app = getApp()
const dayjs = require('../../utils/js/dayjs.js')
import ajax from '../../utils/js/ajax.js'
import props from '../../utils/js/props.js'
Page({
/**
* 页面的初始数据
*/
data: {
player:{},
musics:[
{ audios: [], page: {} }, // 推荐
{ audios: [], page: {} }, // 最热
{ audios: [], page: {} }, // 原创
{ audios: [], page: {} }, // 飙升
{ audios: [], page: {} }, // 最新
],
types: ['推荐', '最热', '原创', '飙升', '最新'],
currentType: 0,
swiperHeight: 0,
startX: 0,
endX: 0,
lineWidth: 0,
lineLeft: 0,
loadingArr: [0, 0, 0, 0, 0],
p: 1
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.getList()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
this.updatePlayer()
},
updatePlayer(){
props.setPlayer.call(this, app.player)
},
getList(){
const type = this.data.currentType;
let loadingArr = this.data.loadingArr
loadingArr[type] = 1
this.setData({ loadingArr })
ajax.get('audio', { type, p: this.data.p }).then(res => {
loadingArr[type] = 0
this.setData({ loadingArr })
if (res.code === 0) {
let { audios, i_resource, a_resource, page } = res.data
this.saveMusics({ type, page, audios }, ()=>{
this.getSwiperHeight((swiperHeight) => this.setData({ swiperHeight }))
})
props.setPlayer.call(this, { i_resource, a_resource })
props.setPlayer.call(this, { list: this.data.musics[type].audios })
}
})
},
saveMusics(data, cb){
let { type, page, audios } = data;
let musics = this.data.musics
musics[type].audios = musics[type].audios.concat(audios)
musics[type].page = page
this.setData({ musics }, ()=>{
cb && cb()
})
},
dateFormat(t){
return dayjs(t * 1000).format('YYYY.MM.DD')
},
changeAudio(e){
let currentType = e.currentTarget.dataset.k
this.setData({ currentType })
},
handleChangeIndex(e) {
let currentType = e.detail.current
let p = this.data.musics[currentType].page.p || 1
props.setPlayer.call(this, { list: this.data.musics[currentType].audios })
//console.log(app.player.list)
this.setData({ p, currentType }, () => {
if (this.data.musics[currentType].audios.length === 0) {
this.getList()
}
this.getSwiperHeight((swiperHeight) => this.setData({ swiperHeight }))
})
},
getSwiperHeight(cb) {
var query = wx.createSelectorQuery().in(this)
query.select('.swiperShow').boundingClientRect(function (res) {
cb && cb(res.height)
}).exec()
},
toDetail(event){
let { e, i } = event.currentTarget.dataset
props.setPlayer.call(this, { current_music: i })
wx.navigateTo({
url: `/pages/music/detail?id=${e.id}`
})
},
handleTouchStart(e) {
let startX = e.touches[0].clientX
this.setData({ startX })
},
handleTouchMove(e) {
let endX = e.touches[0].clientX
if (endX - this.data.startX > 0) {
this.setData({ lineLeft: (endX - this.data.startX) / 10, lineWidth: (endX - this.data.startX) / 10 })
} else {
this.setData({ lineWidth: (this.data.startX - endX) / 10 })
}
},
handleTouchEnd(e) {
this.setData({ lineWidth: 0, lineLeft: 0 })
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
let currentType = this.data.currentType
if (this.data.loadingArr[currentType] !== 0) return
if (this.data.musics[currentType].page.p >= this.data.musics[currentType].page.total_page) {
let loadingArr = this.data.loadingArr
loadingArr[currentType] = 2
this.setData({ loadingArr })
return
}
let p = this.data.musics[currentType].page.p + 1
this.setData({ p }, ()=>{
this.getList()
})
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
================================================
FILE: pages/music/list.json
================================================
{
"usingComponents": {
"loadmore": "/components/loadmore",
"playerBar": "/components/player"
}
}
================================================
FILE: pages/music/list.wxml
================================================
{{v}}
{{e.name}}
{{e.singer.name}}
{{time.dateFormat(e.date)}}
================================================
FILE: pages/music/list.wxss
================================================
/* pages/music/list.wxss */
.typeTitle{
width: 100%;
position: fixed;
left: 0;
top: 0;
z-index: 999;
background: #fff;
border-bottom: 1px solid #eee;
}
.typeList{
height: 1.8rem;
padding-bottom: 0.4rem;
font-size: 0.7rem;
color: #333;
align-items: flex-end;
}
.typeItem{
width: 20%;
transition: all 0.3s;
text-align: center;
}
.itemShow{
font-size: 0.9rem;
color: #33c9d4;
}
.navSwiper{
position: relative;
}
.navSlider{
width: 20%;
height: 2px;
position: absolute;
bottom: -1px;
transition: all 0.5s;
}
.navLine{
height: 100%;
background: #33c9d4;
width: 60%;
margin-left: 20%;
}
.swiper{
width: 100%;
padding-top: 2rem;
padding-bottom: 3rem;
}
.swiperShow{
width: 100%;
padding-top: 2rem;
padding-bottom: 3rem;
max-height: auto;
}
.item{
color: #333;
padding: 1rem 0.75rem 0.5rem 0.75rem;
border-top: 1px solid #eee;
align-items: center;
}
.swiper .item:first-child, .swiperShow .item:first-child{
border: none;
}
.item .item_cover{
width: 4rem;
height: 4rem;
border-radius: 50%;
}
.item_show{
color: #fff;
background: url('http://audio.22family.com//gif/playing.gif') 0 0 /cover;
}
.item .item_info{
width: 100%;
min-height: 4rem;
padding: 0.5rem 0;
padding-left: 1rem;
}
.item .item_info .item_name{
font-size: 0.8rem;
align-self: flex-start;
}
.item .item_info .singer_name{
align-items: center;
padding: 0.7rem 0 0.3rem 0;
font-size: 0.7rem;
color: #666;
}
.item .item_info .singer_name .singer_avatar{
width: 1.4rem;
display: flex;
justify-content: center;
align-items: center;
margin-right: 0.4rem;
}
.item .item_info .singer_name .avatar_img{
width: 1rem;
height:1rem;
border-radius: 50%;
}
.item .item_info .item_date{
font-size: 0.6rem;
color: #999;
}
================================================
FILE: project.config.json
================================================
{
"description": "项目配置文件",
"packOptions": {
"ignore": []
},
"setting": {
"urlCheck": true,
"es6": true,
"postcss": true,
"minified": true,
"newFeature": true,
"autoAudits": false
},
"compileType": "miniprogram",
"libVersion": "2.6.2",
"appid": "wx7d3aad6d394ff0ab",
"projectname": "mySkey",
"debugOptions": {
"hidedInDevtools": []
},
"isGameTourist": false,
"condition": {
"search": {
"current": -1,
"list": []
},
"conversation": {
"current": -1,
"list": []
},
"plugin": {
"current": -1,
"list": []
},
"game": {
"currentL": -1,
"list": []
},
"miniprogram": {
"current": 0,
"list": [
{
"id": -1,
"name": "播放页",
"pathName": "pages/music/detail",
"query": "id=3",
"scene": null
}
]
}
}
}
================================================
FILE: utils/js/ajax.js
================================================
let api_url = 'https://www.22family.com/music/test/'
export default{
get(url, data){
return new Promise((resolve, reject)=>{
wx.request({
url: api_url + url,
method: 'GET',
data,
header: {
'content-type': 'application/json' // 默认值
},
success(res) {
resolve(res.data)
},
error(err){
reject(err)
}
})
})
},
post(url, data) {
return new Promise((resolve, reject) => {
wx.request({
url: api_url + url,
method: 'POST',
data,
header: {
'content-type': 'application/json' // 默认值
},
success(res) {
resolve(res.data)
},
error(err) {
reject(err)
}
})
})
}
}
================================================
FILE: utils/js/audio.js
================================================
================================================
FILE: utils/js/common.js
================================================
export default {
toast(title, duration = 1500){
wx.showToast({
title,
icon: 'none',
duration
})
},
confirm(content, cb){
wx.showModal({
title: '温馨提示',
content,
success(res) {
if (res.confirm) {
cb && cb()
}
}
})
},
showLoading(title){
wx.showLoading({
title
})
},
hideLoading(){
wx.hideLoading()
},
analysis(str) {
str = str.slice(str.indexOf('00:00.00'))
let s = str.replace(/[\s\r\n]/g, "").split('[');
let timeArr = [], lrcArr = [];
for (let v of s) {
let lrc = v.split(']')
timeArr.push(lrc[0])
lrcArr.push(lrc[1])
}
return { timeArr, lrcArr }
},
getAudioTime(num = 0) {
let minute = Math.floor(num / 60).toString();
let second = Math.floor(num % 60).toString();
return `${minute.padStart(2, '0')} : ${second.padStart(2, '0')}`
},
getSecond(t) {
let minute = Number(t.slice(0, 2))
let second = Number(t.slice(3, 5))
let minS = Number(t.slice(7))
return minS > 100 ? (minute * 60 + second + minS / 1000) : (minute * 60 + second + minS / 100)
},
}
================================================
FILE: utils/js/dayjs.js
================================================
!function (t, e) { "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : t.dayjs = e() }(this, function () { "use strict"; var t = "millisecond", e = "second", n = "minute", r = "hour", s = "day", i = "week", a = "month", u = "year", c = /^(\d{4})-?(\d{1,2})-?(\d{0,2})(.*?(\d{1,2}):(\d{1,2}):(\d{1,2}))?.?(\d{1,3})?$/, o = /\[.*?\]|Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, h = { name: "en", weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_") }, d = function (t, e, n) { var r = String(t); return !r || r.length >= e ? t : "" + Array(e + 1 - r.length).join(n) + t }, f = { padStart: d, padZoneStr: function (t) { var e = Math.abs(t), n = Math.floor(e / 60), r = e % 60; return (t <= 0 ? "+" : "-") + d(n, 2, "0") + ":" + d(r, 2, "0") }, monthDiff: function (t, e) { var n = 12 * (e.year() - t.year()) + (e.month() - t.month()), r = t.clone().add(n, "months"), s = e - r < 0, i = t.clone().add(n + (s ? -1 : 1), "months"); return Number(-(n + (e - r) / (s ? r - i : i - r))) }, absFloor: function (t) { return t < 0 ? Math.ceil(t) || 0 : Math.floor(t) }, prettyUnit: function (c) { return { M: a, y: u, w: i, d: s, h: r, m: n, s: e, ms: t }[c] || String(c || "").toLowerCase().replace(/s$/, "") }, isUndefined: function (t) { return void 0 === t } }, $ = "en", l = {}; l[$] = h; var m = function (t) { return t instanceof D }, y = function (t, e, n) { var r; if (!t) return null; if ("string" == typeof t) l[t] && (r = t), e && (l[t] = e, r = t); else { var s = t.name; l[s] = t, r = s } return n || ($ = r), r }, M = function (t, e) { if (m(t)) return t.clone(); var n = e || {}; return n.date = t, new D(n) }, S = function (t, e) { return M(t, { locale: e.$L }) }, p = f; p.parseLocale = y, p.isDayjs = m, p.wrapper = S; var D = function () { function h(t) { this.parse(t) } var d = h.prototype; return d.parse = function (t) { var e, n; this.$d = null === (e = t.date) ? new Date(NaN) : p.isUndefined(e) ? new Date : e instanceof Date ? e : "string" == typeof e && /.*[^Z]$/i.test(e) && (n = e.match(c)) ? new Date(n[1], n[2] - 1, n[3] || 1, n[5] || 0, n[6] || 0, n[7] || 0, n[8] || 0) : new Date(e), this.init(t) }, d.init = function (t) { this.$y = this.$d.getFullYear(), this.$M = this.$d.getMonth(), this.$D = this.$d.getDate(), this.$W = this.$d.getDay(), this.$H = this.$d.getHours(), this.$m = this.$d.getMinutes(), this.$s = this.$d.getSeconds(), this.$ms = this.$d.getMilliseconds(), this.$L = this.$L || y(t.locale, null, !0) || $ }, d.$utils = function () { return p }, d.isValid = function () { return !("Invalid Date" === this.$d.toString()) }, d.$compare = function (t) { return this.valueOf() - M(t).valueOf() }, d.isSame = function (t) { return 0 === this.$compare(t) }, d.isBefore = function (t) { return this.$compare(t) < 0 }, d.isAfter = function (t) { return this.$compare(t) > 0 }, d.year = function () { return this.$y }, d.month = function () { return this.$M }, d.day = function () { return this.$W }, d.date = function () { return this.$D }, d.hour = function () { return this.$H }, d.minute = function () { return this.$m }, d.second = function () { return this.$s }, d.millisecond = function () { return this.$ms }, d.unix = function () { return Math.floor(this.valueOf() / 1e3) }, d.valueOf = function () { return this.$d.getTime() }, d.startOf = function (t, c) { var o = this, h = !!p.isUndefined(c) || c, d = function (t, e) { var n = S(new Date(o.$y, e, t), o); return h ? n : n.endOf(s) }, f = function (t, e) { return S(o.toDate()[t].apply(o.toDate(), h ? [0, 0, 0, 0].slice(e) : [23, 59, 59, 999].slice(e)), o) }; switch (p.prettyUnit(t)) { case u: return h ? d(1, 0) : d(31, 11); case a: return h ? d(1, this.$M) : d(0, this.$M + 1); case i: return d(h ? this.$D - this.$W : this.$D + (6 - this.$W), this.$M); case s: case "date": return f("setHours", 0); case r: return f("setMinutes", 1); case n: return f("setSeconds", 2); case e: return f("setMilliseconds", 3); default: return this.clone() } }, d.endOf = function (t) { return this.startOf(t, !1) }, d.$set = function (i, c) { switch (p.prettyUnit(i)) { case s: this.$d.setDate(this.$D + (c - this.$W)); break; case "date": this.$d.setDate(c); break; case a: this.$d.setMonth(c); break; case u: this.$d.setFullYear(c); break; case r: this.$d.setHours(c); break; case n: this.$d.setMinutes(c); break; case e: this.$d.setSeconds(c); break; case t: this.$d.setMilliseconds(c) }return this.init(), this }, d.set = function (t, e) { return this.clone().$set(t, e) }, d.add = function (t, c) { var o = this; t = Number(t); var h, d = p.prettyUnit(c), f = function (e, n) { var r = o.set("date", 1).set(e, n + t); return r.set("date", Math.min(o.$D, r.daysInMonth())) }, $ = function (e) { var n = new Date(o.$d); return n.setDate(n.getDate() + e * t), S(n, o) }; if (d === a) return f(a, this.$M); if (d === u) return f(u, this.$y); if (d === s) return $(1); if (d === i) return $(7); switch (d) { case n: h = 6e4; break; case r: h = 36e5; break; case e: h = 1e3; break; default: h = 1 }var l = this.valueOf() + t * h; return S(l, this) }, d.subtract = function (t, e) { return this.add(-1 * t, e) }, d.format = function (t) { var e = this, n = t || "YYYY-MM-DDTHH:mm:ssZ", r = p.padZoneStr(this.$d.getTimezoneOffset()), s = this.$locale(), i = s.weekdays, a = s.months, u = function (t, e, n, r) { return t && t[e] || n[e].substr(0, r) }; return n.replace(o, function (t) { if (t.indexOf("[") > -1) return t.replace(/\[|\]/g, ""); switch (t) { case "YY": return String(e.$y).slice(-2); case "YYYY": return String(e.$y); case "M": return String(e.$M + 1); case "MM": return p.padStart(e.$M + 1, 2, "0"); case "MMM": return u(s.monthsShort, e.$M, a, 3); case "MMMM": return a[e.$M]; case "D": return String(e.$D); case "DD": return p.padStart(e.$D, 2, "0"); case "d": return String(e.$W); case "dd": return u(s.weekdaysMin, e.$W, i, 2); case "ddd": return u(s.weekdaysShort, e.$W, i, 3); case "dddd": return i[e.$W]; case "H": return String(e.$H); case "HH": return p.padStart(e.$H, 2, "0"); case "h": case "hh": return 0 === e.$H ? 12 : p.padStart(e.$H < 13 ? e.$H : e.$H - 12, "hh" === t ? 2 : 1, "0"); case "a": return e.$H < 12 ? "am" : "pm"; case "A": return e.$H < 12 ? "AM" : "PM"; case "m": return String(e.$m); case "mm": return p.padStart(e.$m, 2, "0"); case "s": return String(e.$s); case "ss": return p.padStart(e.$s, 2, "0"); case "SSS": return p.padStart(e.$ms, 3, "0"); case "Z": return r; default: return r.replace(":", "") } }) }, d.diff = function (t, c, o) { var h = p.prettyUnit(c), d = M(t), f = this - d, $ = p.monthDiff(this, d); switch (h) { case u: $ /= 12; break; case a: break; case "quarter": $ /= 3; break; case i: $ = f / 6048e5; break; case s: $ = f / 864e5; break; case r: $ = f / 36e5; break; case n: $ = f / 6e4; break; case e: $ = f / 1e3; break; default: $ = f }return o ? $ : p.absFloor($) }, d.daysInMonth = function () { return this.endOf(a).$D }, d.$locale = function () { return l[this.$L] }, d.locale = function (t, e) { var n = this.clone(); return n.$L = y(t, e, !0), n }, d.clone = function () { return S(this.toDate(), this) }, d.toDate = function () { return new Date(this.$d) }, d.toArray = function () { return [this.$y, this.$M, this.$D, this.$H, this.$m, this.$s, this.$ms] }, d.toJSON = function () { return this.toISOString() }, d.toISOString = function () { return this.toDate().toISOString() }, d.toObject = function () { return { years: this.$y, months: this.$M, date: this.$D, hours: this.$H, minutes: this.$m, seconds: this.$s, milliseconds: this.$ms } }, d.toString = function () { return this.$d.toUTCString() }, h }(); return M.extend = function (t, e) { return t(e, D, M), M }, M.locale = y, M.isDayjs = m, M.unix = function (t) { return M(1e3 * t) }, M.en = l[$], M });
================================================
FILE: utils/js/props.js
================================================
const app = getApp()
export default class Props{
static setPlayer(player, cb=null){
app.player = Object.assign({}, app.player, player)
this.setData({ player: app.player }, ()=>{
cb && cb()
})
}
static setPlaying(playing, cb=null){
app.player.playing = Object.assign({}, app.player.playing, playing)
this.setData({ player: app.player }, ()=>{
cb && cb()
})
}
}
================================================
FILE: utils/wxs/time.wxs
================================================
// wxs中只支持到es4的语法,所以别使用es6
module.exports = {
getAudioTime: function(num) {
num = Number(num)
var minute = Math.floor(num / 60)
var second = Math.floor(num % 60)
return ( minute>9 ? minute : '0'+minute) + ' : ' + (second>9 ? second : '0'+second)
},
dateFormat: function(t) {
var date = getDate(t * 1000)
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
return year + '.' + (month>9 ? month : '0' + month) + '.' + (day>9 ? day : '0' + day)
}
}
================================================
FILE: utils/wxss/icon.wxss
================================================
@font-face {font-family: "iconfont";
src: url('//at.alicdn.com/t/font_1101476_zl0zw7wq9p8.eot?t=1553943371044'); /* IE9 */
src: url('//at.alicdn.com/t/font_1101476_zl0zw7wq9p8.eot?t=1553943371044#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
url('//at.alicdn.com/t/font_1101476_zl0zw7wq9p8.woff?t=1553943371044') format('woff'),
url('//at.alicdn.com/t/font_1101476_zl0zw7wq9p8.ttf?t=1553943371044') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('//at.alicdn.com/t/font_1101476_zl0zw7wq9p8.svg?t=1553943371044#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-news:before {
content: "\e63d";
}
.icon-last-play:before {
content: "\e60b";
}
.icon-next-play:before {
content: "\e611";
}
.icon-music:before {
content: "\e794";
}
.icon-menu:before {
content: "\e62e";
}
.icon-only:before {
content: "\e607";
}
.icon-error:before {
content: "\e766";
}
.icon-loading:before {
content: "\e65d";
}
.icon-suiji:before {
content: "\e802";
}
.icon-next:before {
content: "\e60f";
}
.icon-fm:before {
content: "\e65b";
}
.icon-pause:before {
content: "\e620";
}
.icon-play:before {
content: "\e621";
}
================================================
FILE: utils/wxss/reset.wxss
================================================
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
================================================
FILE: utils/wxss/style.wxss
================================================
html{
font-size: 7.3333333333vw;
background: #fff;
-moz-user-select: none; /*火狐*/
-webkit-user-select: none; /*webkit浏览器*/
-ms-user-select: none; /*IE10*/
-khtml-user-select: none; /*早期浏览器*/
user-select: none;
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
view{
margin: 0;
padding: 0;
}
ul>li{
list-style: none;
}
.df{
display: flex;
}
.df-1{
flex: 1;
}
.df-col{
display: flex;
flex-direction: column;
}
.df-j-b{
display: flex;
justify-content: space-between;
}
.df-j-c{
display: flex;
justify-content: center;
}