歌词滚动效果
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- 设置标签页图标 --><link rel="shortcut icon" href="./favicon.ico" type="image/x-icon"><title>Document</title><style>html {background: #000;color: aliceblue;width: 100%;height: 100%;}body {display: flex;flex-direction: column;width: 100%;height: 100%;overflow: hidden;}ul, li {margin: 0;padding: 0;}.head {flex: none;display: flex;justify-content: center;align-items: center;padding: 30px 0;}img {width: 100px;height: 100px;border-radius: 50%;margin-right: 20px;}.right {display: flex;flex-direction: column;justify-content: center;}.des {margin: 6px;padding-left: 7px;}audio {width: 600px;height: 60px;}.content {flex: 1;overflow: hidden;margin: 0;}#list {list-style: none;transition: .5s ease;}.lyric {text-align: center;height: 40px;line-height: 40px;transition: 0.2s;}.active {/* font-size: 20px; // 过渡会引起回流,推荐使用tranform */transform: scale(1.2);color: aquamarine;}</style>
</head>
<body><div class="head"><img src="http://p3fx.kgimg.com/uploadpic/softhead/120/20241213/20241213201306973919.jpg" /><div class="right"><p class="des">江语晨-最后一页</p><!-- 加controls这个属性才能看到audio标签 --><audio controls autoplay src = "https://sharefs.tx.kugou.com/202505141511/3fdf7e70100a2d282f80b08266c04d5d/v3/653e2f76f69079273c79f65fecf58aea/yp/full/ap1000_us0_pi409_s2981929298.mp3"></div></div><div class="content"><ul id="list"></ul></div><script> const lyr = "[00:00.00]滴滴音乐网 www.dda5.com\n[00:00.20]\n[00:00.56]雨停滞天空之间\n[00:04.07]像泪在眼眶盘旋\n[00:07.90]这也许是最后一次见面\n[00:15.43]沿途经过的从前\n[00:19.14]还来不及再重演\n[00:23.86]拥抱早已悄悄冷却\n[00:30.84]海潮声 淹没了离别时的黄昏\n[00:38.36]只留下不舍的体温\n[00:45.70]星空下 拥抱着快凋零的温存\n[00:52.96]爱只能在回忆里完整\n[01:03.92]想把你抱进身体里面\n[01:09.45]不敢让你看见\n[01:13.09]嘴角那颗没落下的泪\n[01:19.73]如果这是最后的一页\n[01:24.34]在你离开之前\n[01:28.08]能否让我把故事重写\n[02:38.01]雨停滞天空之间\n[02:41.62]像泪在眼眶盘旋\n[02:45.45]这也许是最后一次见面\n[02:53.00]沿途经过的从前\n[02:56.70]还来不及再重演\n[03:01.47]拥抱早已悄悄冷却\n[03:08.49]海潮声 淹没了离别时的黄昏\n[03:15.89]只留下不舍的体温\n[03:23.26]星空下 拥抱着快凋零的温存\n[03:30.52]爱只能在回忆里完整\n[03:37.83]想把你抱进身体里面\n[03:43.08]不敢让你看见\n[03:46.85]嘴角那颗没落下的泪\n[03:52.90]如果这是最后的一页\n[03:58.10]在你离开之前\n[04:01.81]能否让我把故事重写\n[04:08.04]想把你抱进身体里面\n[04:13.23]不敢让你看见\n[04:16.83]嘴角那颗没落下的泪\n[04:22.88]如果这是最后的一页\n[04:28.12]在你离开之前\n[04:31.83]能否让我把故事重写\n";const avatar = "http://p3fx.kgimg.com/uploadpic/softhead/120/20241213/20241213201306973919.jpg";const src = "https://sharefs.tx.kugou.com/202505141511/3fdf7e70100a2d282f80b08266c04d5d/v3/653e2f76f69079273c79f65fecf58aea/yp/full/ap1000_us0_pi409_s2981929298.mp3";const audio = document.querySelector('audio');audio.src = src;const lyrics = lyr.split('\n').filter(v => v).map((item) => {// const matchs = item.match(/\[(\S+)\](\S*)/);const [_, time, sentence] = item.split(/[\[\]]/); // 根据[或]符号分割const [minute, second] = time.split(':'); // 00:30.84const fTime = +minute * 60 + +second;return { time: fTime, sentence };});console.log('lyrics', lyrics);const content = document.querySelector('.content');const list = document.querySelector('#list');// 创建一个文档片段,把所有dom的操作先应用在这个片段上,之后将片段加入文档,就可以做到将多次dom操作合并成一次,提高效率。const frag = document.createDocumentFragment();lyrics.forEach(({ sentence }) => {const li = document.createElement('div');//innerText和textContent的区别;attributes和property的区别li.innerText = sentence;// add remove toggleli.classList.add('lyric');// 操作dom树次数过多,需要优化frag.appendChild(li);});list.appendChild(frag);// console.dir(list);audio.play();// 监听歌曲进度,设置歌词偏移量const contentHeight = content.clientHeight;const listHeight = list.clientHeight;const lyricHeight = list.children[0].clientHeight;const minOffset = 0;const maxOffset = listHeight - contentHeight;const scrollSentence = () => {const currentTime = audio.currentTime;const index = lyrics.findIndex(({ time }) => time > currentTime);const currentIndex = index < 0 ? lyrics.length - 1 : index - 1;let offset = currentIndex * lyricHeight + lyricHeight / 2 - contentHeight / 2;if (offset < 0) {offset = 0;}if (offset > maxOffset) {offset = maxOffset;}list.style.transform = `translateY(-${offset}px)`;const activeLi = list.querySelector('.active');if (activeLi) {activeLi.classList.remove('active');}const li = list.children[currentIndex];if (li) {li.classList.add('active');}}audio.ontimeupdate = (e) => {scrollSentence();};</script>
</body>
</html>
效果: