一、實現(xiàn)效果
- 點擊播放按鈕歌曲進(jìn)行播放刽锤,點擊暫停停止播放
- 顯示歌曲當(dāng)前播放時間和總時間
- 隨著歌曲播放進(jìn)度條變紅,點擊進(jìn)度條任意位置都可以到達(dá)(快進(jìn)操作)
- 歌唱哪句歌詞高亮具篇,一句結(jié)束自動滾動
注意:實現(xiàn)整個效果膘融,需要將每個步驟的代碼整合在一起
二舷夺、步驟
1.搭建靜態(tài)頁面
<!--pages/music1/index.wxml-->
<view class="container">
<!-- 歌名和演唱者 -->
<view class="header">
<view>三十歲的女人</view>
<view class="author">趙雷</view>
</view>
<!-- 歌詞部分茵瘾,可滾動 -->
<scroll-view class="middle" scroll-y="true">
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>歌詞放置處</view>
<view>末尾</view>
</scroll-view>
<!-- 底部進(jìn)度條 -->
<view class="footer">
<view class="progress-bar">
<view>00:00</view>
<view class="progress-line">
<view class="progress-bg"></view>
<view class="progress-red"></view>
<view class="progress-dot">
<icon class="iconfont iconyuandian1"></icon>
</view>
</view>
<view>00:00</view>
</view>
</view>
<!-- 操作按鈕 -->
<view class="btn-group">
<view class="prev">
<icon class="iconfont iconshangyishou"></icon>
</view>
<view class="play">
<icon class="iconfont iconweibiaoti--"></icon>
</view>
<view class="next">
<icon class="iconfont iconxiayishou"></icon>
</view>
</view>
</view>
@import '/assets/fonts/iconfont.wxss';
.container {
width: 100vw;
height: 100vh;
background: #000;
color: #fff;
}
.header {
padding: 20rpx;
line-height: 30px;
text-align: center;
}
.header .author{
font-size: 16px;
}
.middle{
height: 55vh;
text-align: center;
margin-top: 20px;
font-size: 16px;
}
.middle view{
height: 60rpx;
line-height: 60rpx;
}
.footer{
padding: 10px;
width: 100%;
box-sizing: border-box;
margin-top: 30px;
}
.progress-bar{
display: flex;
justify-content: space-between;
align-items: center;
}
.progress-line{
flex: 1;
margin: 0 5px;
position: relative;
}
.progress-bg{
width: 100%;
background: #fff;
height: 4rpx;
}
.progress-red{
width: 30%;
height:100%;
position: absolute;
background: red;
top: 0;
left: 0;
}
.progress-dot{
position: absolute;
top: -15px;
left: -5px;
}
.btn-group{
display: flex;
justify-content: center;
align-items: center;
}
.play{
margin: 0 5px;
}
.play icon{
font-size: 50px;
}
.prev icon, .next icon{
font-size: 30px;
}
2.點擊播放按鈕歌曲進(jìn)行播放踢关,點擊暫停停止播放
思路:使用
isplaying來控制樣式,false顯示播放圖標(biāo),歌曲暫停播放,true顯示暫停圖標(biāo),歌曲播放
- 2.1放置
audio
,不顯示在頁面中
<audio src="{{src}}" id="myAudio" >
- 2.2點擊播放圖標(biāo)可以切換為暫停圖標(biāo),并且可以控制歌曲的播放和暫停
<view class="play" bindtap="changeState">
<icon class="iconfont {{isplaying===false?' iconweibiaoti--':'iconzanting'}}"></icon>
</view>
data: {
isplaying: false, //控制
src: 'http://audio01.dmhmusic.com/71_53_T10046221715_128_4_1_0_sdk-cpm/0206/M00/6D/81/ChR47FsrnyWAKVx0AE-m4DXLKqo190.mp3?xcode=039efb32a1d055924b8d829e8d3f68b006abe09', //音樂地址
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面顯示
*/
onShow: function() {
// 獲取當(dāng)前頁面的audio
this.audioCtx = wx.createAudioContext('myAudio')
},
changeState() {
if (!this.data.isplaying) {
this.audioCtx.play()//歌曲播放
} else {
this.audioCtx.pause()//歌曲暫停
}
this.setData({
isplaying: !this.data.isplaying
})
},
3.顯示歌曲當(dāng)前播放時間和總時間,隨著歌曲播放進(jìn)度條變紅,
點擊進(jìn)度條任意位置都可以到達(dá)(快進(jìn),后退操作);
思路
- 播放時會觸發(fā)
bindtimeupdate
,獲取當(dāng)前時間currentTime
和歌曲總時間duration
;- 定義變量
progressPercent
控制progress-red
的寬度,progress-dot
的left;- 獲取當(dāng)前位置
offsetX
占progress-line寬度width
百分比p
,使用this.audioCtx.seek(p在總時間的占比)跳轉(zhuǎn)歌曲的位置(實現(xiàn)快進(jìn)后退)
<view class="progress-line" bindtap="seek">
<view class="progress-bg"></view>
<view class="progress-red" style="width:{{progressPercent}}%;"></view>
<view class="progress-dot" style="left:calc({{progressPercent}}% - 5px)">
<icon class="iconfont iconyuandian1"></icon>
</view>
</view>
data: {
currentTime: '00:00', //當(dāng)前時間
duration: "00:00", //總時間
progressPercent: 0, //百分比笼吟,控制寬度
width: 0, //獲取progress-line的寬度
durationTime:0,//總時間库物,跳轉(zhuǎn)指定位置使用
},
// 化為時分秒
formatMs2Obj(total) {
var h = this.repairZero(Math.floor(total / 3600))
var m = this.repairZero(Math.floor((total - h * 3600) / 60))
var s = this.repairZero(Math.floor(total - h * 3600 - m * 60))
//ES6 結(jié)構(gòu) h:h
return {
h,
m,
s
}
},
/**
* 補(bǔ)零
*/
repairZero(num) {
return num < 10 ? ("0" + num) : num
},
timeupdate(e) {
var obj1 = this.formatMs2Obj(e.detail.currentTime)
var obj2 = this.formatMs2Obj(e.detail.duration)
var str1 = obj1.m + ":" + obj1.s
var str2 = obj2.m + ":" + obj2.s
//
if (this.data.currentTime !== str1) {
// 更新當(dāng)前時間
this.setData({
currentTime: str1,
progressPercent: e.detail.currentTime * 100 / e.detail.duration
})
}
// 賦值總時間,每次總時間一致不用賦值
if (this.data.duration !== str2) {
this.data.durationTime=e.detail.duration//總時間
this.setData({
duration: str2
})
}
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面加載
*/
onLoad: function(options) {
// 獲取節(jié)點贷帮,獲取progress-line寬度width
var query = wx.createSelectorQuery()
var that = this;
query.select('.progress-line').boundingClientRect(function(rect) {
that.setData({
width: rect.width//寬度
})
}).exec();
},
seek(e) {
// 點擊白色進(jìn)度條任意位置戚揭,紅色進(jìn)度條到達(dá)點擊處
// 獲取當(dāng)前位置
var offsetX = e.touches[0].pageX - e.currentTarget.offsetLeft
// 獲取當(dāng)前位置站總寬度的百分比
var p = offsetX / this.data.width
// seek跳轉(zhuǎn)至指定位置,
// this.data.durationTime*p,獲取位置百分比在總時間中的占比
this.audioCtx.seek(this.data.durationTime*p)
}
4.歌曲播放哪句歌詞高亮撵枢,結(jié)束后歌詞自動滾動(到第六行的時候在滾動)
思路
- 找到歌詞lrc(帶時間的),存儲在easy-mock中(也可以根據(jù)需求存儲在其他位置)民晒,需要在數(shù)組中增加分割的字符(此處加的是;)
- 分割歌詞,最終目標(biāo)數(shù)組分割成
[{time:" ",text:" "}]
,需要使用split,trim,substr
split() 方法用于把一個字符串分割成字符串?dāng)?shù)組
trim()去除字符串兩端的空格
substr() 方法可在字符串中抽取從 start 下標(biāo)開始的指定數(shù)目的字符
- 循環(huán)數(shù)組songtext來顯示歌詞
- 定義變量
activeIndex
控制高亮,activeIndex
等于i- scrolltop設(shè)置滾動距離,當(dāng)i>5的時候才可以滾動
<scroll-view class="middle" scroll-y="true" scroll-top="{{scrolltop}}">
<view wx:for="{{songtext}}" class="{{activeIndex===index?'active':''}}">{{item.text}}</view>
</scroll-view>
data: {
songtext: '', //歌詞
activeIndex: 0, //控制高亮
scrolltop: 0 //滾動距離
},
onLoad:function(){
// 獲取歌詞,請求easy-mock數(shù)據(jù)
wx.request({
url: 'https://www.easy-mock.com/mock/5d032195cccf932f99d7422e/xcx/songtext',
success: res => {
var arr = res.data.songtext.split(";")
// console.log(arr)
arr = arr.map(r => {
// 去除每一項的空格很重要,不然后面設(shè)置當(dāng)前項是空格的锄禽,上一項不是空格仍然高亮不起作用
var arr1 = r.trim().substr(1).split("]")
return {
time: arr1[0],
text: arr1[1]
}
})
this.setData({
songtext: arr
})
}
})
},
timeupdate(e) {
//控制高亮
// 循環(huán)數(shù)組
for (var i = 0; i < this.data.songtext.length; i++) {
// 當(dāng)前播放時間等于數(shù)組time時activeIndex才改變值
if (this.data.currentTime === this.data.songtext[i].time) {
// 當(dāng)activeIndex不等于i時更新潜必,當(dāng)songtext有值為空格時也不更新
if (this.data.activeIndex !== i && this.data.songtext[i].text) {
this.setData({
activeIndex: i,
scrolltop: 30 * (i - 5)
})
if (i > 5) {
this.setData({
// 此處的滾動距離可以為高度*i,到第5行在進(jìn)行滾動
scrolltop: 30 * (i - 5)
})
}
break
}
}
}
}