需求
实现歌词滚动效果,类似网易云音乐播放界面。
实现
1.准备数据
后台一般会返回这样一个歌词数据,每个时间都对应当前这个歌词。
因为是字符串不方便直接使用,我们把他转化为对象格式。封装一个utils工具传入歌词把lyric转化为对象。
ini
// 处理后端返回歌词
export const HandleLyric = (lyric) => {
function convertToSeconds(timeArray) {
// 获取分钟和秒(包括毫秒)
const minutes = parseFloat(timeArray[0]); // 使用parseFloat来确保即使分钟有小数部分也能正确处理
const secondsWithMilliseconds = parseFloat(timeArray[1]);
// 计算总秒数
const totalSeconds = minutes * 60 + secondsWithMilliseconds;
return totalSeconds;
}
let line = lyric.split('\n')
let value1 = []
for (let i = 0; i < line.length; i++) {
let str = line[i]
// 把字符串分割为数组
let part = str.split(']')
let timestr = part[0].substring(1)
let parts = timestr.split(':')
let obj = {
time: convertToSeconds(parts),
word: part[1]
}
value1.push(obj)
}
return value1
}
2.计算偏移量
准备audio标签
xml
<div class="audio">
<el-button>立即播放/暂停</el-button>
<audio :src="audio_info['url']" ref="audio" class="audio-sty">11</audio>
</div>
调用audio标签的currentTime 可以获取当前歌曲播放到第几秒,遍历歌词的时间和当前时间(currentTime)比较,返回的i就是当前歌词的在第几行。
javascript
const changeplay = () => {
let audio = document.querySelector('.audio-sty')
// 找到当前这一句歌词的索引
function FindIndex() {
let currentTime = audio.currentTime
for (var i = 0; i < store.lyicWords.length; i++) {
if (currentTime < store.lyicWords[i].time) {
return i - 1
}
}
return store.lyicWords.length - 1
}
}
计算偏移量
ini
// 计算偏移量
/**
* 偏移量
* @containerHeight //容器高度
* @PHeight //单个歌词高度
*/
function Setoffset() {
var index = FindIndex()
var offset = index * store.PHeight + store.PHeight / 2 - store.containerHeight / 2
if (offset < 0) {
offset = 0
}
store.index = index
store.Offset = offset
}
用当前歌词所偏移的大小加上单个歌词Height1/2的大小,就可以实现歌词偏移,如果想让每次高亮的歌词在中间,需要再减去container盒子自身Height的一半。
调用audio的timeupadte时间触发计算偏移函数
less
// audio 时间变化事件
audio.addEventListener('timeupdate', Setoffset)
3.添加样式
xml
<div class="center" ref="center">
<h1>歌词</h1>
<el-card class="box-center">
<div class="center-ci" style="overflow: auto;" ref="lyricHeight">
<p v-for="(item, index) in songList['txt']" v-if="songList['txt'].length != 0"
:class="[index == store.index ? 'active' : '']">{{item }}</p>
<p v-else>纯音乐,无歌词</p>
</div>
</el-card>
</div>
使用transform: translateY(-50px);控制偏移
使用transform: scale(1.2);控制文字大小
css
.center-ci {
transform: translateY(-50px);
display: block;
height: 100%;
width: 100%;
p {
transition: 0.2s;
font-size: 20px;
text-align: center;
}
.active {
transform: scale(1.2);
color: goldenrod;
}
}
给歌词容器设置transform就可以实现歌词偏移了
ini
// 根据偏移量滚动歌词
lyricHeight.value.style.transform = `translateY(-${store.Offset}px)`
4.效果
~谢谢观看