JS实现歌词滚动效果
核心思路:
-
处理歌词数据:
{time:开始时间(s), word:歌词} -
计算出当前播放器对应应该显示的歌词的索引
-
创建每句歌词的
<li>元素,并将歌词对象的word属性插入列表的textContent中
(优化:可使用DocumentFragment一次性插入DOM) -
计算
<ul>的偏移量:let offset = liHeight*currentIndex + liHeight/2 - containerHeight/2
对边缘情况处理:offset < 0 ? offset = 0 : offsetconst maxOffset = dom.ul.scrollHeight - containerHeightoffset > maxOffset ? offset = maxOffset : offset
-
为当前对应的
<li>元素添加CSS类 -
监听播放器的timeupdate事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>歌词滚动案例</title>
<link rel="shortcut icon" href="./assets/music.svg" type="image/x-icon">
<link rel="stylesheet" href="./style/index4.css">
</head>
<body>
<audio src="./assets/告解.mp3" controls></audio>
<div class="container">
<ul class="lyricList">
</ul>
</div>
<script src="./js/data.js"></script>
<script src="./js/index4.js"></script>
</body>
</html>
*{
margin: 0;
padding: 0;
}
li{
list-style: none;
}
body{
background-color: #000;
color: #666;
font-size: 26px;
}
audio{
width: 600px;
margin: 10px auto;
display: block;
}
.container{
width: 600px;
height: 800px;
margin: 50px auto;
text-align: center; /* 对其中的行盒子元素实现居中 */
overflow: hidden;
}
/* 控制容器的相对位置实现歌词的滚动
1. 通过margin-top实现歌词的滚动会导致浏览器重排,影响性能
2. 可以通过transform:translateY()实现歌词的滚动,避免重排 */
.lyricList{
transition:0.2s;
}
.lyricList li{
height: 50px;
line-height: 50px;
transition: 0.2s;
}
.active{
color: #fff;
/* font-size: 2em; // 导致重排 */
transform: scale(1.2);
}
/**
* 解析歌词字符串
* {time: 开始时间, word: 歌词}
*/
function parseLrc(){
var lines = lrc.split('\n');
var lrcList = [];
for(var i = 0; i < lines.length; i++){
var line = lines[i]
var obj={
time: parseTime(line.split('[')[1].split(']')[0]),
word: line.split(']')[1]
}
lrcList.push(obj)
}
return lrcList
}
/**
* 解析时间字符串
* @param {string} str 时间字符串,格式为mm:ss
* @returns 时间秒数
*/
function parseTime(str){
var time = str.split(':');
var min = Number(time[0]);
var sec = Number(time[1]);
return min * 60 + sec;
}
var lrcData = parseLrc()
const dom = {
audio: document.querySelector('audio'),
ul: document.querySelector('ul'),
constainer: document.querySelector('.container')
}
/**
* 计算出当前播放器对应应该显示的歌词的索引
*/
function findIndex(){
const currentTime = dom.audio.currentTime;
for(var i = 0; i < lrcData.length; i++){
var item = lrcData[i];
if(item.time > currentTime){
return i - 1;
}
}
return lrcData.length - 1;
}
function createLrcElement(){
const frag = document.createDocumentFragment()
for(let i=0;i<lrcData.length;i++){
const li = document.createElement('li')
li.textContent = lrcData[i].word
frag.appendChild(li) // 每次创建都会改动DOM树,但是需要等出现性能问题时才针对性优化,不要率先优化
}
dom.ul.appendChild(frag)
}
createLrcElement()
/**
* 设置ul元素偏移量
*/
var containerHeight = dom.constainer.clientHeight
var liHeight = dom.ul.children[0].clientHeight
function setOffset(){
const currentIndex = findIndex()
let offset = liHeight*currentIndex + liHeight/2 - containerHeight/2
offset < 0 ? offset = 0 : offset
const maxOffset = dom.ul.scrollHeight - containerHeight
offset > maxOffset ? offset = maxOffset : offset
dom.ul.style.transform = `translateY(${-offset}px)`
let li = document.querySelector('.active')
li?.classList.remove('active')
li = dom.ul.children[currentIndex]
li?.classList.add('active')
}
dom.audio.addEventListener('timeupdate', setOffset)
var lrc = `[00:0.0]告解
[00:3.0]演唱:世界之外
[00:4.0]
[00:25.68]那天西城又雨落
[00:28.56]像旧日的惶惑
[00:33.45]心动心乱恍如昨
[00:36.63]我在雨夜失措
[00:40.32]控制失落痴迷执着
[00:44.28]爱是自由的沦落
[00:47.40]我就看着我
[00:50.22]清醒地堕落
[00:55.29]我告诉我没结果
[00:58.08]心动是错
[01:00.36]答案不是我
[01:02.91]强求换不得你为我
[01:05.94]留下与我
[01:08.04]真心亦是错
[01:10.86]我告诉我不应得
[01:13.68]短暂交汇
[01:15.81]依然平行错过
[01:18.63]你不属于我
[01:20.37]只留下我
[01:23.55]清醒地沦落
[01:26.55]求不得
[01:28.05]号码从此不被拨
[01:46.83]像从未出现过
[01:51.54]你离开后天晴过
[01:54.72]我的回忆雨落
[01:58.41]污名荣耀寂寞喧嚣
[02:02.31]爱是明知的执着
[02:05.46]我就看着我
[02:08.67]一再地踏错
[02:13.35]我告诉我不要错
[02:16.17]既知无果
[02:18.39]不要再爱了
[02:21.06]可这个世界多寂寞
[02:24.03]若没有你
[02:26.13]还能做什么
[02:29.16]我告诉我要放过
[02:31.62]成全你我
[02:33.51]给你你想要的
[02:36.72]我愿让你飞
[02:38.52]就留下我
[02:41.43]困守地执着
[02:44.76]不易得
[03:02.13]我告诉我不要错
[03:04.98]既知无果
[03:07.17]不要再爱了
[03:09.84]可这个世界多寂寞
[03:12.81]若不爱你
[03:14.85]还能做什么
[03:17.70]我告诉我要放过
[03:18.27]成全你我
[03:25.26]给你你想要的
[03:25.65]我愿让你飞
[03:27.36]就留下我
[03:30.30]困守地执着
[03:33.54]在等着
[03:55.0]`

浙公网安备 33010602011771号