js实现歌词同步
实现歌词同步的基本思路
歌词同步的核心是通过音频播放时间与歌词时间戳匹配,动态高亮当前播放的歌词行。需要将歌词文本解析为结构化数据(时间+文本),监听音频时间变化并更新UI。
歌词解析
歌词通常以LRC格式存储,每行格式为[mm:ss.xx]歌词文本。解析示例:

function parseLRC(lrcText) {
const lines = lrcText.split('\n');
return lines.map(line => {
const timeMatch = line.match(/^\[(\d{2}):(\d{2})\.(\d{2})\]/);
if (!timeMatch) return null;
const min = parseInt(timeMatch[1]);
const sec = parseInt(timeMatch[2]);
const centisec = parseInt(timeMatch[3]);
const time = min * 60 + sec + centisec * 0.01;
return {
time,
text: line.replace(timeMatch[0], '').trim()
};
}).filter(item => item);
}
同步逻辑实现
创建歌词同步控制器类,处理时间比对与UI更新:

class LyricSync {
constructor(lrcData, audioElement) {
this.lrcArray = lrcData;
this.audio = audioElement;
this.currentIndex = 0;
this.domElements = [];
}
init(container) {
this.lrcArray.forEach((item, index) => {
const div = document.createElement('div');
div.textContent = item.text;
div.dataset.index = index;
container.appendChild(div);
this.domElements.push(div);
});
}
update() {
const currentTime = this.audio.currentTime;
// 查找当前应高亮的歌词行
let activeIndex = this.lrcArray.findIndex(
(item, idx) => currentTime < this.lrcArray[idx + 1]?.time || idx === this.lrcArray.length - 1
);
if (activeIndex !== -1 && activeIndex !== this.currentIndex) {
this.domElements[this.currentIndex]?.classList.remove('active');
this.currentIndex = activeIndex;
this.domElements[this.currentIndex]?.classList.add('active');
this.scrollToCurrent();
}
}
scrollToCurrent() {
const element = this.domElements[this.currentIndex];
element?.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
使用示例
// 假设已有音频元素和歌词容器
const audio = document.getElementById('audio');
const lrcContainer = document.getElementById('lyrics');
const lrcText = `[00:01.00]第一行歌词\n[00:05.30]第二行歌词\n[00:10.20]第三行歌词`;
// 初始化
const parsedLRC = parseLRC(lrcText);
const lyricSync = new LyricSync(parsedLRC, audio);
lyricSync.init(lrcContainer);
// 添加时间更新监听
audio.addEventListener('timeupdate', () => lyricSync.update());
样式增强建议
为高亮当前歌词添加CSS样式:
#lyrics div {
padding: 8px;
transition: all 0.3s;
}
#lyrics div.active {
color: #ff0000;
font-size: 1.2em;
font-weight: bold;
}
性能优化方向
对于长歌词列表,可采用虚拟滚动技术减少DOM节点数量。监听时间更新时使用requestAnimationFrame节流:
let isUpdating = false;
audio.addEventListener('timeupdate', () => {
if (!isUpdating) {
requestAnimationFrame(() => {
lyricSync.update();
isUpdating = false;
});
isUpdating = true;
}
});






