上一篇
html如何实现歌词滚动播放
- 前端开发
- 2025-07-14
- 3195
HTML中,通过结合CSS和JavaScript,可以实现歌词滚动播放,使用“标签嵌入音频,利用JavaScript监听音频
播放时间,动态调整歌词列表的位置,并配合CSS实现平滑滚动效果
HTML中实现歌词滚动播放,需要结合HTML、CSS和JavaScript来完成,以下是详细的实现步骤和相关代码示例:
HTML结构搭建
创建一个基本的HTML结构,包含音频播放控件和用于显示歌词的容器。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0">歌词滚动播放</title> <link rel="stylesheet" href="styles.css"> </head> <body> <audio id="audioPlayer" src="song.mp3" controls></audio> <div class="lyrics-container"> <ul id="lyricsList"></ul> </div> <script src="script.js"></script> </body> </html>
CSS样式设计
使用CSS来设置歌词容器的样式,包括高度、溢出隐藏等,以及歌词列表项的样式。
body { font-family: Arial, sans-serif; background-color: #f0f0f0; text-align: center; } .lyrics-container { width: 500px; height: 200px; margin: 20px auto; overflow: hidden; border: 1px solid #ccc; background-color: #fff; } #lyricsList { list-style: none; padding: 0; margin: 0; transition: transform 0.5s ease-in-out; } #lyricsList li { height: 30px; line-height: 30px; text-align: center; } .active { color: red; font-weight: bold; }
JavaScript逻辑实现
JavaScript是实现歌词滚动播放的核心部分,主要负责解析歌词文件、同步音频播放进度、更新歌词显示等。
1 解析歌词文件
歌词文件采用LRC格式,包含时间戳和歌词内容,我们需要编写一个函数来解析这种格式的歌词文件。
function parseLrc(lrcText) { const lines = lrcText.split('n'); const lyrics = []; lines.forEach(line => { const match = line.match(/[(d{2}):(d{2}).(d{2})](.+)/); if (match) { const minutes = parseInt(match[1], 10); const seconds = parseInt(match[2], 10); const milliseconds = parseInt(match[3], 10); const time = minutes 60 + seconds + milliseconds / 100; const word = match[4]; lyrics.push({ time, word }); } }); return lyrics; }
2 加载歌词文件
可以使用fetch
API来异步加载歌词文件,并将其传递给解析函数。
fetch('lyrics.lrc') .then(response => response.text()) .then(lrcText => { const lyrics = parseLrc(lrcText); renderLyrics(lyrics); }) .catch(error => console.error('Error loading lyrics:', error));
3 渲染歌词到页面
将解析后的歌词数据动态生成到HTML列表中。
function renderLyrics(lyrics) { const lyricsList = document.getElementById('lyricsList'); lyricsList.innerHTML = ''; // 清空现有列表 lyrics.forEach(lyric => { const li = document.createElement('li'); li.textContent = lyric.word; lyricsList.appendChild(li); }); }
4 同步音频播放与歌词高亮
通过监听音频的timeupdate
事件,获取当前播放时间,并与歌词的时间戳进行比较,找到当前应该高亮的歌词项。
const audioPlayer = document.getElementById('audioPlayer'); let currentIndex = 0; audioPlayer.addEventListener('timeupdate', () => { const currentTime = audioPlayer.currentTime; const lyrics = Array.from(document.querySelectorAll('#lyricsList li')); let found = false; for (let i = 0; i < lyrics.length; i++) { const lyricTime = lyrics[i].dataset.time; if (currentTime >= lyricTime) { currentIndex = i; found = true; } else { break; } } if (!found) { currentIndex = lyrics.length 1; } updateLyricsHighlight(currentIndex); });
5 更新歌词高亮显示
根据当前索引,更新歌词列表项的高亮状态。
function updateLyricsHighlight(index) { const lyrics = document.querySelectorAll('#lyricsList li'); lyrics.forEach((lyric, i) => { if (i === index) { lyric.classList.add('active'); } else { lyric.classList.remove('active'); } }); }
处理歌词滚动
当歌词列表项超过容器高度时,需要滚动歌词以保持当前歌词在可视区域内,可以通过调整transform
属性来实现平滑滚动。
function scrollLyricsToCurrent() { const lyricsContainer = document.query.contains('.lyrics-container'); const lyricsList = document.getElementById('lyricsList'); const currentLyric = lyricsList.children[currentIndex]; const containerHeight = lyricsContainer.clientHeight; const listItemHeight = currentLyric.clientHeight; const scrollOffset = currentLyric.offsetTop (containerHeight listItemHeight) / 2; lyricsList.style.transform = `translateY(-${scrollOffset}px)`; }
在updateLyricsHighlight
函数中调用scrollLyricsToCurrent
函数,确保每次高亮更新时都检查并调整滚动位置。
完整示例代码整合
将上述各部分代码整合在一起,形成一个完整的实现。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0">歌词滚动播放</title> <style> body { font-family: Arial, sans-serif; background-color: #f0f0f0; text-align: center; } .lyrics-container { width: 500px; height: 200px; margin: 20px auto; overflow: hidden; border: 1px solid #ccc; background-color: #fff; } #lyricsList { list-style: none; padding: 0; margin: 0; transition: transform 0.5s ease-in-out; } #lyricsList li { height: 30px; line-height: 30px; text-align: center; } .active { color: red; font-weight: bold; } </style> </head> <body> <audio id="audioPlayer" src="song.mp3" controls></audio> <div class="lyrics-container"> <ul id="lyricsList"></ul> </div> <script> function parseLrc(lrcText) { const lines = lrcText.split('n'); const lyrics = []; lines.forEach(line => { const match = line.match(/[(d{2}):(d{2}).(d{2})](.+)/); if (match) { const minutes = parseInt(match[1], 10); const seconds = parseInt(match[2], 10); const milliseconds = parseInt(match[3], 10); const time = minutes 60 + seconds + milliseconds / 100; const word = match[4]; lyrics.push({ time, word }); } }); return lyrics; } fetch('lyrics.lrc') .then(response => response.text()) .then(lrcText => { const lyrics = parseLrc(lrcText); renderLyrics(lyrics); }) .catch(error => console.error('Error loading lyrics:', error)); function renderLyrics(lyrics) { const lyricsList = document.getElementById('lyricsList'); lyricsList.innerHTML = ''; // 清空现有列表 lyrics.forEach(lyric => { const li = document.createElement('li'); li.textContent = lyric.word; li.dataset.time = lyric.time; // 存储时间戳以便后续使用 lyricsList.appendChild(li); }); } const audioPlayer = document.getElementById