js实现歌词同步
歌词同步的基本原理
歌词同步的核心是将歌词文本与音频时间轴匹配,根据当前播放时间动态高亮显示对应歌词。通常需要解析LRC格式的歌词文件(包含时间标签),并监听音频播放进度。
解析LRC歌词格式
LRC歌词格式示例:
[00:00.00]歌曲名
[00:01.50]第一句歌词
[00:04.30]第二句歌词
解析函数示例:
function parseLRC(lrcText) {
const lines = lrcText.split('\n');
const result = [];
lines.forEach(line => {
const timeTags = line.match(/\[(\d{2}):(\d{2})\.(\d{2})\]/g);
const text = line.replace(/\[.*?\]/g, '').trim();
if (timeTags && text) {
timeTags.forEach(tag => {
const minutes = parseInt(tag.match(/\[(\d{2}):/)[1]);
const seconds = parseInt(tag.match(/:(\d{2})\./)[1]);
const milliseconds = parseInt(tag.match(/\.(\d{2})\]/)[1]);
const time = minutes * 60 + seconds + milliseconds / 100;
result.push({ time, text });
});
}
});
return result.sort((a, b) => a.time - b.time);
}
实现歌词同步渲染
创建歌词渲染函数,根据当前播放时间更新显示:
function setupLyricSync(audioElement, lrcData, container) {
let currentLine = 0;
audioElement.addEventListener('timeupdate', () => {
const currentTime = audioElement.currentTime;
while (currentLine < lrcData.length - 1 &&
currentTime >= lrcData[currentLine + 1].time) {
currentLine++;
}
while (currentLine > 0 && currentTime < lrcData[currentLine].time) {
currentLine--;
}
renderLyrics(lrcData, currentLine, container);
});
}
function renderLyrics(lrcData, currentLine, container) {
container.innerHTML = '';
lrcData.forEach((line, index) => {
const p = document.createElement('p');
p.textContent = line.text;
p.className = index === currentLine ? 'active' : '';
container.appendChild(p);
});
}
CSS样式增强
添加基础样式提升视觉效果:
.lyrics-container {
text-align: center;
line-height: 2;
font-size: 16px;
}
.lyrics-container p.active {
color: #1db954;
font-size: 18px;
font-weight: bold;
}
完整使用示例
// 获取DOM元素
const audio = document.getElementById('audio-player');
const lyricsContainer = document.getElementById('lyrics-container');
// 模拟LRC歌词数据
const lrcText = `
[00:01.50]这是第一句歌词
[00:04.30]这是第二句歌词
[00:07.20]这是第三句歌词
`;
// 解析并设置同步
const lrcData = parseLRC(lrcText);
setupLyricSync(audio, lrcData, lyricsContainer);
高级优化建议
添加平滑滚动效果,使当前歌词始终保持在可视区域中间位置:
function renderLyrics(lrcData, currentLine, container) {
container.innerHTML = '';
let activeElement = null;
lrcData.forEach((line, index) => {
const p = document.createElement('p');
p.textContent = line.text;
if (index === currentLine) {
p.className = 'active';
activeElement = p;
}
container.appendChild(p);
});
if (activeElement) {
activeElement.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
}
处理无歌词情况
添加占位提示提升用户体验:

function renderLyrics(lrcData, currentLine, container) {
if (!lrcData.length) {
container.innerHTML = '<p class="no-lyrics">暂无歌词</p>';
return;
}
// ...原有渲染逻辑
}






