前言
在很多音乐播放平台,都会有音频播放器和歌词同步显示功能,本文将介绍如何利用纯前端的方法实现歌词滚动效果。
1. 解析歌词数据
通常,歌词数据的存储格式为 .lrc 文件,它包含了歌词的时间戳和对应的歌词内容。
通过解析这些数据,我们可以得到歌词对象。
function parseLrc() {
var lines = lrc.split('\n');
var result = []; // 歌词对象数组
for (var i = 0; i < lines.length; i++) {
var str = lines[i];
var parts = str.split(']');
var timeStr = parts[0].substring(1);
var obj = {
time: parseTime(timeStr),
words: parts[1],
};
result.push(obj);
}
return result;
}
function parseTime(timeStr) {
var parts = timeStr.split(':');
return +parts[0] * 60 + +parts[1];
}
在这段代码中,我们通过 parseLrc 这个函数解析歌词字符串,获取每一句歌词的开始时间和歌词内容。
然后再使用 parseTime 这个函数将时间字符串被转换为秒数,便于后续的时间比对。
2. 显示歌词
下一步,我们需要把这些歌词元素渲染到网页上。
我们可以遍历解析每条歌词数据,为每一句歌词创建一个 li 元素,并将其添加到外面的 ul 列表中。
function createLrcElements() {
var frag = document.createDocumentFragment();
for (var i = 0; i < lrcData.length; i++) {
var li = document.createElement('li');
li.textContent = lrcData[i].words;
frag.appendChild(li);
}
doms.ul.appendChild(frag);
}
3. 根据当前播放时间计算歌词滚动
根据音频播放的时间来动态调整歌词的显示位置。
每当播放器的时间发生变化时,我们需要计算当前播放到哪一秒,进而找到应该高亮显示的歌词行。
function findIndex() {
var curTime = doms.audio.currentTime;
for (var i = 0; i < lrcData.length; i++) {
if (curTime < lrcData[i].time) {
return i - 1;
}
}
return lrcData.length - 1;
}
4. 设置歌词滚动偏移量
为了后续实现滚动效果,我们需要计算出歌词列表 (ul) 的偏移量,使得当前播放的歌词行位于视口的中央。
通过计算当前歌词行的索引,我们可以设置 ul 元素的 transform 属性来实现滚动。
function setOffset() {
var index = findIndex();
var offset = liHeight * index + liHeight / 2 - containerHeight / 2;
if (offset < 0) {
offset = 0;
}
if (offset > maxOffset) {
offset = maxOffset;
}
doms.ul.style.transform = `translateY(-${offset}px)`;
// 高亮当前歌词
var li = doms.ul.querySelector('.active');
if (li) {
li.classList.remove('active');
}
li = doms.ul.children[index];
if (li) {
li.classList.add('active');
}
}
此函数的作用是根据计算的偏移量设置 ul 元素的 translateY 值,从而使歌词内容随音频进度滚动。
同时,添加上 active 类来高亮显示当前正在播放的歌词行。
5. 设置样式
为了使歌词滚动效果更为流畅,我们需要通过 CSS 来控制歌词的外观和滚动动画。
设置容器的高度、溢出隐藏和滚动动画,以及为当前歌词行设置高亮样式。
* {
margin: 0;
padding: 0;
}
body {
background: #000;
color: #666;
text-align: center;
}
audio {
width: 450px;
margin: 30px 0;
}
.container {
height: 420px;
overflow: hidden;
}
.container ul {
transition: 0.6s;
list-style: none;
}
.container li {
height: 30px;
line-height: 30px;
transition: 0.2s;
}
.container li.active {
color: #fff;
transform: scale(1.2);
}
这里,我们使用 transition 属性来使歌词滚动和高亮切换更为平滑。
6. 函数调用
给音频绑定 timeupdate 事件,调用 setOffset 函数,使得歌词能够随着音频的播放实时滚动。
doms.audio.addEventListener('timeupdate', setOffset);