1.HTML部分完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入图标 -->
<link rel="shortcut icon" href="./assets/favicon.ico" type="image/x-icon">
<!-- 引入css -->
<link rel="stylesheet" href="./index.css">
</head>
<body>
<audio src="./assets/music.mp3" controls></audio>
<div class="container">
<ul class="lrc-list">
<!-- li由js动态创建,此处只是为了方便观看,可删掉 -->
<li>Fuga nemo ut perspiciatis.</li>
</ul>
</div>
<!-- 引入歌词部分 -->
<script src="./js/data.js"></script>
<script src="./index.js"></script>
</body>
</html>
2.css部分完整代码
*{
margin: 0;
padding: 0;
}
body{
background-color: black;
color: #6b6a6a;
text-align: center;
}
audio{
margin: 10px 0;
width: 450px;
}
.container{
border: 1px solid red;
height: 400px;
overflow: hidden;
}
.container ul{
border: 1px solid rgb(221, 203, 203);
/* 滚动动画过渡时间 */
transition: 0.5s;
/* 歌词向上滚动偏移,用js来控制 */
transform: translateY(0px);
}
.container li{
list-style: none;
text-align: center;
left: 30px;
height: 30px;
/* 激活样式过度时间 */
transition: 0.4s;
}
.container li.active{
color: #fff;
/* 激活字体放大,使用transform比font-size性能更好 */
transform: scale(1.5) ;
}
3.js部分代码详解
0.获取dom元素
1.先解析歌词字符串为数组
2. 计算出,在当前播放器播放到第几秒的情况下, lcrData数组中,应该高亮显示歌词下标,如 果没有歌词需要显示则得到-1
3.创建歌词元素
4.歌词滚动偏移量计算
4.1图解
4.2代码分解
5.js部分完整代码
//获取dom元素
let doms = {
ul: document.querySelector("ul"),
audio: document.querySelector("audio"),
container: document.querySelector(".container")
}
/**
* 解析歌词字符串
* 得到一个歌词对象的数组
* 每个歌词对象
* {time:歌词开始的时间,words:歌词内容}
*/
function parseLrc() {
let lcrArr = []//定义空变量保存数组
let lines = lrc.split("\n")//以换行分隔符把歌词转为数组
for (let i = 0; i < lines.length; i++) { //循环得到数组的每一项
let parseSrc = lines[i].split("]")//把数组每一项拆分为数组
let timeSrc = parseSrc[0].substring(1)//获取到时间字符串
let obj = { //拼接对象
tiem: parseTime(timeSrc),
words: parseSrc[1]
}
lcrArr.push(obj) //把对象添加到数组中
}
return lcrArr
}
/**
* 将一个时间字符串处理为数字(秒)
* @param timeStr 时间字符串
* @returns 返回数字
*/
function parseTime(time) {
let tiemArr = time.split(":")//把时间字符串拆分为数组
return tiemArr[0] * 60 + +tiemArr[1] //返回具体的数字时间 +运算符可以把字符串转成数字
}
let lrcData = parseLrc()
console.log(lrcData)
/**
* 计算出,在当前播放器播放到第几秒的情况下
* lcrData数组中,应该高亮显示歌词下标
* 如果没有歌词需要显示则得到-1
*/
function findIndex() {
let currentTime = doms.audio.currentTime//当前播放时间
for (let i = 0; i < lrcData.length; i++) {
if (currentTime < lrcData[i].tiem) {
return i - 1 //返回歌词下标
}
}
return lrcData.length - 1//如果找完了都还没有找的就返回最后一句歌词的下标
}
/**
* 创建歌词元素
*/
function createElement() {
for (let i = 0; i < lrcData.length; i++) {
let li = document.createElement('li')//创建li标签
li.textContent = lrcData[i].words//往li标签里面添加内容
doms.ul.appendChild(li)//把li标签添加到ul标签下
}
}
createElement()
/**
* 设置当前播放时间ul元素的偏移量
*/
let containerHeight = doms.container.clientHeight//获取容器高度
let ulHeight = doms.ul.clientHeight//获取ul高度
let liHeight = doms.ul.children[0].clientHeight//获取单个li高度
let maxOffset = ulHeight - containerHeight//偏移最大高度
function setOffset() {
let offset = findIndex() * liHeight + 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');//获取所有带active类名的的节点赋值给li
if (li) {
li.classList.remove('active')//移除active
}
//添加新样式
li = doms.ul.children[findIndex()]//获取当前播放元素赋值给li
if (li) {
li.classList.add('active')//给当前li添加active激活样式
}
}
/**
* 添加交互事件timeupdate播放位置改变时触发
*/
doms.audio.addEventListener("timeupdate", setOffset)