歌词滚动效果实现
- 歌词滚动效果
- HTML部分
- CSS部分
- JS部分
- 解析歌词字符串,得到歌词的对象数组
- 计算在当前情况下,播放器播放到第几秒的情况
- 创建歌词元素
- 设置ul元素的偏移量
- 最后对时间变化的事件进行监听
- 完整JS代码
歌词滚动效果
- 实现效果如图所示:
首先准备一个歌曲MP3文件,以及歌词,将歌词放入一个
data.js
文件中。
- 歌词内容如下所示:
HTML部分
- 歌词采用ul-li的结构进行展示
- 导入相应的css和js文件
- 代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link rel="stylesheet" href="./css/index.css">
</head>
<body><audio src="./assets/薛之谦 - 狐狸.mp3" controls></audio><div class="container"><ul> </ul></div><script src="./js/data.js"></script><script src="./js/index.js"></script>
</body>
</html>
CSS部分
- 由于CSS属性变化本身没有动画效果,因此这里采用
transition
属性实现其动画效果 transition
属性只针对于数值嘞的属性有效- 代码如下:(大家可以根据自己的喜好设置样式)
*{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.3s;}
.container li{height: 30px;line-height: 30px;transition: 0.3s;list-style: none;}
.container li.active{color: #fff;transform: scale(1.2);
}
JS部分
解析歌词字符串,得到歌词的对象数组
// 解析时间字符串
function parseTime(timeStr){let parts = timeStr.split(':');return +parts[0]*60 + +parts[1];
}
/*** 解析歌词字符串,得到歌词的对象数组* 每个歌词对象 * {time: 开始时间, words:歌词内容}*/
function parseLrc(){var result = [];var lines = lrc.split('\n'); // 字符串数组for(let i = 0; i < lines.length; i++){// 遍历lineslet str = lines[i]; //每一句歌词字符串let parts = str.split(']'); //分割let timeStr = parts[0].substring(1); //截取时间var obj ={time:parseTime(timeStr),words: parts[1]}result.push(obj);}return result;
}var lrcData = parseLrc();
计算在当前情况下,播放器播放到第几秒的情况
/*** 计算在当前情况下,播放器播放到第几秒的情况* lrcData数组中应该高亮显示的歌词下标*/
function findIndex(){// 获取播放器的当前时间let curTime = doms.audio.currentTime;for(let i = 0; i<lrcData.length; i++){if(curTime<lrcData[i].time){return i-1;}}// 如果没有任何一句歌词显示,则返回-1// 如果找遍了都没有找到,说明播放到最后一句return lrcData.length-1;
}
创建歌词元素
// 创建歌词元素
function createLrcElement(){for(let i=0; i<lrcData.length; i++){let li = document.createElement('li');li.textContent = lrcData[i].words;doms.ul.appendChild(li);}
}
设置ul元素的偏移量
// 容器高度
var containerHeight = doms.container.clientHeight;
// li高度
var liHeight = doms.ul.children[0].clientHeight;
// 最大高度
var maxOffset = doms.ul.clientHeight - containerHeight;// 设置ul元素的偏移量
function setOffset(){let 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)`;// 去掉之前的active样式let li1 = doms.ul.querySelector('.active');if(li1){li1.classList.remove('active');}let li2 = doms.ul.children[index];if(li2){li2.classList.add('active');}}
最后对时间变化的事件进行监听
doms.audio.addEventListener('timeupdate', setOffset);
如果大家没有MP3文件或者歌词的话,我会上传我的资源,可以自行下载。
完整JS代码
var doms = {audio:document.querySelector('audio'),ul:document.querySelector('.container ul'),container:document.querySelector('.container')
}// 解析时间字符串
function parseTime(timeStr){let parts = timeStr.split(':');return +parts[0]*60 + +parts[1];
}/*** 解析歌词字符串,得到歌词的对象数组* 每个歌词对象 * {time: 开始时间, words:歌词内容}*/
function parseLrc(){var result = [];var lines = lrc.split('\n'); // 字符串数组for(let i = 0; i < lines.length; i++){// 遍历lineslet str = lines[i]; //每一句歌词字符串let parts = str.split(']'); //分割let timeStr = parts[0].substring(1); //截取时间var obj ={time:parseTime(timeStr),words: parts[1]}result.push(obj);}return result;
}var lrcData = parseLrc();/*** 计算在当前情况下,播放器播放到第几秒的情况* lrcData数组中应该高亮显示的歌词下标*/
function findIndex(){// 获取播放器的当前时间let curTime = doms.audio.currentTime;for(let i = 0; i<lrcData.length; i++){if(curTime<lrcData[i].time){return i-1;}}// 如果没有任何一句歌词显示,则返回-1// 如果找遍了都没有找到,说明播放到最后一句return lrcData.length-1;
}// 创建歌词元素
function createLrcElement(){for(let i=0; i<lrcData.length; i++){let li = document.createElement('li');li.textContent = lrcData[i].words;doms.ul.appendChild(li);}
}
createLrcElement()// 容器高度
var containerHeight = doms.container.clientHeight;
// li高度
var liHeight = doms.ul.children[0].clientHeight;
// 最大高度
var maxOffset = doms.ul.clientHeight - containerHeight;// 设置ul元素的偏移量
function setOffset(){let 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)`;// 去掉之前的active样式let li1 = doms.ul.querySelector('.active');if(li1){li1.classList.remove('active');}let li2 = doms.ul.children[index];if(li2){li2.classList.add('active');}}// 事件监听
doms.audio.addEventListener('timeupdate', setOffset);```