效果图
HTML
<view class="box">
<!-- 毛玻璃 -->
<view class="bgImage">
<image src="{{img}}" />
</view>
<view class="top">
<view class="topcen" wx:if="{{showlyric===false}}">
<image src="{{img}}" class="{{stop===true?'urlpi':'urlpic'}}"></image>
</view>
</view>
<!-- 滑块上面 -->
<view class="up">
<view wx:for="{{up}}" wx:key="index" class="topfor">
<image src="{{item}}" style="width:40rpx;height:40rpx"></image>
</view>
</view>
<!-- 滑块左右的时间 -->
<view class="timeall">
<view class="time">
<view>{{nowtime}}</view>
<view>{{showTotalTime}}</view>
</view>
</view>
<!-- 滑块 -->
<slider value="{{value}}" inactive-color="rgb(112, 112, 112)" active-color="red" class="mid" min="0" max="{{maxtiem}}" step="1" bindchange="change" bindchanging="changeing" />
<!-- 下面icon -->
<view class="down">
<view wx:for="{{down}}" wx:key="index" class="downfor">
<!-- 播放/暂停按钮 -->
<image wx:if="{{index===2 && stop===true}}" src="{{item}}" bindtap="stop" style="width:90rpx;height:90rpx"></image>
<image wx:if="{{index===2 && stop===false}}" src="../../images/stop.png" bindtap="stop" style="width:90rpx;height:90rpx"></image>
<!-- 列表循环/单曲循环/随机播放图标 -->
<image wx:if="{{index===0 && cycle ===0}}" src="../../images/cycle.png" bindtap="random" style="width:45rpx;height:45rpx"></image>
<image wx:if="{{index===0 && cycle ===1}}" src="../../images/Single_cycle.png" bindtap="random" style="width:45rpx;height:45rpx"></image>
<image wx:if="{{index===0 && cycle ===2}}" src="{{item}}" bindtap="random" style="width:45rpx;height:45rpx"></image>
<!-- 其他图标 -->
<image wx:if="{{index===1}}" src="{{item}}" bindtap="above" style="width:45rpx;height:45rpx"></image>
<image wx:if="{{index===3}}" src="{{item}}" bindtap="following" style="width:45rpx;height:45rpx"></image>
<image wx:if="{{index===4}}" src="{{item}}" bindtap="stop" style="width:45rpx;height:45rpx"></image>
</view>
</view>
<!-- 歌词 -->
<view class="bom" bindtap="showlyric">
<view catchlongtap="lyr">
<scroll-view scroll-y="true" class="{{showlyric===true?'display':'none'}}" style="height:600rpx;" scroll-with-animation scroll-top="{{location*30}}" wx:if="{{showlyric===true}}" scroll-top="{{location*32}}" bindscroll="scroll" bindtouchstart="start" bindtouchend="end">
<view style="height:284rpx"></view>
<view wx:for="{{lyric}}" wx:key="index" class="lyricfor" style="text-align:center;">
<view class="{{location===index?'red1':''}}">{{item}}</view>
</view>
<view style="height:300rpx"></view>
</scroll-view>
</view>
</view>
<!-- 歌名,歌手 -->
<view class="song">
<view style="margin-top:20rpx">{{songname}}</view>
<view class="singer">
<view wx:for="{{singer}}" wx:key="index" style="margin-left:20rpx">{{item.name}}</view>
</view>
</view>
<!-- 滚动水平线 -->
<view class="center" wx:if='{{isScroll===true}}'>
<view class="center1">
<view>{{lyrictimeshow}}</view>
<view bindtap="goto">播放</view>
</view>
</view>
</view>
JS
import dayjs from '../../lib/dayjs.min.js'
import api from "../../http/api"
let bg = wx.getBackgroundAudioManager() //全局变量
let lineTimeId = '';//水平线定时器
let isDelete = false;//是否删除开启的定时器
Page({
/**
* 页面的初始数据
*/
data: {
cycle: 0, //控制(列表循环0)(单曲循环1)(随机2)
stop: false, //暂停开始判断条件
show: true, //定时器判断
showTotalTime: "00:00",//总时长
value: 0, //滑块绑定的值
nowtime: '00:00',//当前播放的时长
maxtiem: 0,//最大时长
id: '', //发请求用的id
isScroll: false, //是否显示滚动水平线
songname: '', //歌名
singer: [], //演唱者
lyric: [],//歌词
lyrictime: [],//歌词时间
lyrictimeshow: '00:00',//横线指示的时间
location: 0,
locationValue: 0,//歌词滚动具体位置
locationTime: 0,//歌词定位时间
showlyric: false,//是否展示歌词
url: '', //用来装发送拿到url的请求
img: '', //用来装发送拿到图片的请求
index: 0, //用来接受拿到传入index的值
idplay: [], //用来接收传入的id数组
up: [
'../../images/like.png',
'../../images/download.png',
'../../images/vip.png',
'../../images/comments.png',
'../../images/three.png'],
down: [
'../../images/random.png',
'../../images/On_a.png',
'../../images/pla.png',
'../../images/next.png',
'../../images/playlist.png'],
},
//歌词滚动
scroll(e) {
if (this.data.showlyric === true) {
let i = parseInt(e.detail.scrollTop / 32);
// console.log(e.detail.scrollTop, i, "i")
this.setData({
locationTime: this.data.lyric[i],
lyrictimeshow: dayjs(this.data.lyrictime[i] * 1000).format("mm:ss")
});
}
},
//开始
start(e) {
console.log('开始')
this.setData({
isScroll: true,
show: false
})
isDelete = false;
if (lineTimeId) {
clearTimeout(lineTimeId);
lineTimeId = '';
}
},
//歌词拖动点击播放
goto(e) {
//把(mm:ss)转化成(ss)
let a = Number(this.data.lyrictimeshow.split(':')[0] * 60) + Number(this.data.lyrictimeshow.split(':')[1].split('.')[0]);
//跳转
console.log(a, "a")
bg.seek(a)
this.setData({
show: true
})
},
//结束
end(e) {
console.log('结束')
isDelete = true;
if (lineTimeId = !'') {
lineTimeId = setTimeout(() => {
if (isDelete === true) {
this.setData({
isScroll: false
});
lineTimeId = '';
}
}, 4000);
}
//定时器延时启动
setTimeout(() => {
this.setData({
show: true
})
}, 4000)
},
//是否展示歌词
showlyric() {
if (this.data.showlyric === false) {
this.data.showlyric = true
this.setData({
showlyric: this.data.showlyric
})
} else if (this.data.showlyric === true) {
this.data.showlyric = false
this.setData({
showlyric: this.data.showlyric,
isScroll: false
})
}
console.log(this.data.showlyric)
},
//控制播放顺序 列表循环/单曲循环/随机播放
random() {
if (this.data.cycle === 0) {
this.data.cycle = 1
this.setData({
cycle: this.data.cycle
})
} else if (this.data.cycle === 1) {
this.data.cycle = 2
this.setData({
cycle: this.data.cycle
})
} else if (this.data.cycle === 2) {
this.data.cycle = 0
this.setData({
cycle: this.data.cycle
})
}
},
//定时器
playmusic() {
setInterval(() => {
if (this.data.show === true) {
this.data.showTotalTime = dayjs(bg.duration * 1000).format('mm:ss')
this.data.nowtime = dayjs(bg.currentTime * 1000).format('mm:ss')
this.data.maxtiem = parseInt(bg.duration) //解析一个字符传并返回一个整数
this.data.value = parseInt(bg.currentTime)
this.setData({
value: this.data.value,
showTotalTime: this.data.showTotalTime,
nowtime: this.data.nowtime,
maxtiem: this.data.maxtiem
})
if (this.data.showlyric === true) {
for (let i = 0; i < this.data.lyric.length; i++) {
// console.log(this.data.value, this.data.lyrictime[this.data.lyric.length - 1])
if (this.data.value > this.data.lyrictime[this.data.lyric.length - 1]) {//最后的歌词的时间比较
this.setData({
location: this.data.lyric.length - 1,
lyrictimeshow: dayjs(this.data.lyrictime[this.data.lyric.length - 1] * 1000).format('mm:ss')
});
break;
}
// console.log(this.data.nowtime, this.data.lyric[i]);
if (this.data.value >= this.data.lyrictime[i] && this.data.value < this.data.lyrictime[i + 1]) {
// console.log("歌词滚动");
this.setData({
location: i,
lyrictimeshow: dayjs(this.data.lyrictime[i] * 1000).format('mm:ss')
});
break;
}
}
}
// console.log(this.data.showTotalTime, "总时长mm-ss")
// console.log(this.data.nowtime, "当前播放的时长mm-ss")
// console.log(this.data.maxtiem, "最大时长s")
// console.log(this.data.value, "value s")
}
}, 1000)
},
//滑动改变后
change(event) {
bg.seek(event.detail.value)
console.log(event.detail.value, "event.detail.value")
this.data.show = true
this.setData({
show: this.data.show
})
},
//滑动中事件
changeing(event) {
let a = false
this.setData({
show: a,
nowtime: dayjs(event.detail.value * 1000).format('mm:ss')
})
},
//暂停
stop() {
if (this.data.stop === false) {
bg.pause()
this.data.stop = true
this.setData({
stop: this.data.stop
})
} else {
bg.play()
this.data.stop = false
this.setData({
stop: this.data.stop
})
}
},
//获取url
getUrl() {
if (this.data.id) {
api.url(
this.data.id
).then(res => {
if (res.data[0].url) {
this.data.url = res.data[0].url
this.setData({
url: this.data.url
})
bg.src = this.data.url
bg.title = "123"
} else {
this.following()
}
}).catch(err => {
console.log(err)
})
} else { this.following() }
},
//获取图片
getImg() {
api.ids(
this.data.id
).then(res => {
console.log(res.songs[0].al.name)
console.log(res.songs[0].ar)
this.data.songname = res.songs[0].al.name
this.data.singer = res.songs[0].ar
this.data.img = res.songs[0].al.picUrl
this.setData({
img: this.data.img,
songname: this.data.songname,
singer: this.data.singer
})
}).catch(ree => {
console.log(ree)
})
},
//获取歌词
getLyric() {
api.lyric(
this.data.id
).then(res => {
let a = res.lrc.lyric.split('\n')
let ci = [], citime = []
a.map(item => {
// 时间
let time = item.match(new RegExp("\\[[0-9]*:[0-9]*.[0-9]*\\]", "g"))
if (time) {
time = time[0].replace("[", '').replace("]", '')
let it = Number(time.split(':')[0] * 60) + Number(time.split(':')[1].split('.')[0]);
//毫秒:+Number(time.split(':')[1].split('.')[1]);
// console.log(time,dayjs(time).format('mm:ss'));
citime.push(it)
ci.push(item.replace(new RegExp("\\[[0-9]*:[0-9]*.[0-9]*\\]", "g"), ''))
}
})
//去空
let a1 = [], a2 = [];
for (let i = 0; i < ci.length; i++) {
if (citime[i] && ci[i]) {//当前是否有歌词
a1.push(citime[i]);
a2.push(ci[i]);
}
}
this.data.lyrictime = a1
this.data.lyric = a2
this.setData({
lyrictime: this.data.lyrictime,
lyric: this.data.lyric
})
// console.log(this.data.lyrictime, "lyrictime")
// console.log(this.data.lyric, 'lyric')
wx.hideLoading()
}).catch(ree => {
console.log(ree)
})
},
//上一首歌
above() {
this.setData({
stop: false
})
if (this.data.index > 0) {
this.setData({
index: this.data.index - 1
})
this.above1()
} else {
this.setData({
index: this.data.idplay.length - 1
})
this.above1()
}
},
//上一首歌方法
above1() {
this.data.id = this.data.idplay[this.data.index]
this.setData({
id: this.data.id
})
// 发送请求查看该id是否有版权
api.music(
this.data.id
).then(res => {
if (res.success === true) {
this.getImg()
this.getUrl()
this.getLyric()
//当上一首歌曲url地址为null时候继续调用此方法
if (this.data.url === null) {
wx.showToast({
title: "未找到地址,请听上一首",
icon: 'none',
duration: 1000//持续的时间
})
setTimeout(() => {
this.above()
}, 1000)
}
}
}).catch(ree => {
// 如果没有版权
wx.showToast({
title: ree.response.data.message + "请听上一首",
icon: 'none',
duration: 1000//持续的时间
})
//再次调用次此方法查看上一首
setTimeout(() => {
this.above()
}, 1000)
})
},
//下一首歌
following() {
this.setData({
stop: false
})
//判断只有当当前下标不为最后一个时
if (this.data.index * 1 < this.data.idplay.length - 1) {
if (this.data.cycle === 0) { this.data.index = this.data.index * 1 + 1 }
else if (this.data.cycle === 1) { this.data.index = this.data.index }
else if (this.data.cycle === 2) {
let num = parseInt(Math.random() * ((this.data.idplay.length - 1) - 0 + 1) + 0)
this.data.index = num
console.log(num + 1, '第几首歌')
}
this.setData({
index: this.data.index
})
this.data.id = this.data.idplay[this.data.index]
this.setData({
id: this.data.id
})
//发送请求查看该id是否有版权
// 如果有
api.music(
this.data.id
).then(res => {
console.log(res)
this.getImg()
this.getUrl()
this.getLyric()
//当拿到的url为空时候
if (this.data.url === null) {
wx.showToast({
title: "未找到地址,请听下一首",
icon: 'none',
duration: 1000//持续的时间
})
this.following()
}
}).catch(ree => {
// 如果没有有
wx.showToast({
title: ree.response.data.message + "请听一首",
icon: 'none',
duration: 1000//持续的时间
})
//再次调用次此方法查看下一首
setTimeout(() => {
this.following()
}, 1000)
})
} else if (this.data.index * 1 === this.data.idplay.length - 1) {
this.setData({
index: 0
})
console.log(this.data.index, "index")
this.following()
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.showLoading({
title: '加载中',
})
this.data.index = options.index
this.data.idplay = options.id.split(",")
this.setData({
index: this.data.index,
idplay: this.data.idplay
})
this.data.id = this.data.idplay[this.data.index]
this.setData({
id: this.data.id
})
console.log(this.data.id, "id")
this.getImg()
this.getUrl()
this.playmusic()
this.getLyric()
//监听音乐自然结束
bg.onEnded(() => {
//播放下一首
this.following()
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
CSS
.urlpic {
width: 550rpx;
height: 550rpx;
border-radius: 50%;
animation: rock 20s linear infinite;
animation-delay: 0s;
animation-direction: normal;
animation-play-state: running;
}
.urlpi {
width: 550rpx;
height: 550rpx;
border-radius: 50%;
animation: rock 20s linear infinite;
animation-delay: 0s;
animation-direction: normal;
animation-play-state: paused;
}
@keyframes rock {
0% {
transform: rotate(0deg)
}
100% {
transform: rotate(360deg)
}
}
.top {
background-color: rgba(255, 250, 240, 0);
width: 100%;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 150rpx;
}
.topcen {
width: 580rpx;
height: 580rpx;
border-radius: 50%;
border: 1rpx solid rgb(163, 163, 163);
display: flex;
justify-content: center;
align-items: center;
}
.up {
width: 100%;
display: flex;
align-items: center;
position: absolute;
bottom: 400rpx;
}
.down {
width: 100%;
display: flex;
align-items: center;
position: absolute;
bottom: 120rpx;
}
.topfor,
.downfor {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.box {
width: 100%;
height: 100vh;
background-color: rgba(138, 132, 132, 0.479);
}
.play {
width: 80rpx;
height: 80rpx;
}
.middle {
display: flex;
width: 80%;
}
.mid {
width: 70%;
position: absolute;
bottom: 290rpx;
color: rgb(112, 112, 112);
left: 80rpx;
z-index: 6;
}
.time {
width: 97%;
display: flex;
justify-content: space-between;
align-items: center;
color: white;
}
.timeall {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
bottom: 310rpx;
position: absolute;
z-index: 5;
}
.bgImage {
filter: blur(30px);
position: absolute;
height: 100vw;
width: 100vw;
z-index: -1;
}
.bgImage>image {
height: 100vh;
width: 100vw;
}
.bom {
position: absolute;
width: 100%;
height: 65%;
z-index: 7;
top: 20rpx;
display: flex;
justify-content: center;
align-items: center;
}
.alllyric {
display: flex;
align-items: center;
flex-direction: column;
color: white;
height: 500rpx;
font-size: 30rpx;
margin-top: 200rpx;
}
.lyricfor {
margin-top: 20rpx;
width: 550rpx;
color: white;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 30rpx;
}
.lyr {
width: 100%;
height: 60%;
}
.song {
width: 100%;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
color: white;
font-size: 35rpx;
}
.singer {
display: flex;
font-size: 28rpx;
}
.red1 {
color: red;
height: 70rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 33rpx;
}
.display {
display: block;
}
.none {
display: none;
}
.center {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
position: absolute;
top: 34%;
border: 1rpx solid gray;
height: 70rpx;
z-index: 999;
}
.center1 {
display: flex;
justify-content: space-between;
width: 95%;
font-size: 30rpx;
}