fix(music-player): 修复歌词解析和显示问题
- 更新歌词解析正则,支持更广泛的歌词格式 - 修复歌词时间计算,精确到毫秒 -优化无歌词时的处理逻辑,显示每行文本 - 改进歌词滚动逻辑,确保正确显示当前行 - 增加对 currentTime 的监听,实时更新歌词显示
This commit is contained in:
@@ -386,22 +386,29 @@ const parsedLyric = computed(() => {
|
|||||||
const lyric = currentMusic.value.lyric;
|
const lyric = currentMusic.value.lyric;
|
||||||
const lines = lyric.split('\n');
|
const lines = lyric.split('\n');
|
||||||
const result = [];
|
const result = [];
|
||||||
const timeRegExp = /\[(\d{2}):(\d{2})\.(\d+)\]/g;
|
const timeRegExp = /\[(\d{2}):(\d{2})\.(\d{2,3})\]/g;
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const text = line.replace(timeRegExp, '').trim();
|
const text = line.replace(timeRegExp, '').trim();
|
||||||
if (text) {
|
|
||||||
timeRegExp.lastIndex = 0;
|
timeRegExp.lastIndex = 0;
|
||||||
let match;
|
let match;
|
||||||
while ((match = timeRegExp.exec(line)) !== null) {
|
while ((match = timeRegExp.exec(line)) !== null) {
|
||||||
const min = parseInt(match, 10);
|
const min = parseInt(match[1], 10);
|
||||||
const sec = parseInt(match, 10);
|
const sec = parseInt(match[2], 10);
|
||||||
const msStr = match;
|
const msPart = match[3];
|
||||||
const time = min * 60 + sec + parseFloat('0.' + msStr);
|
const msStr = msPart.padEnd(3, '0');
|
||||||
|
const ms = parseInt(msStr, 10);
|
||||||
|
const time = min * 60 + sec + ms / 1000;
|
||||||
|
if (text) {
|
||||||
result.push({ time, text });
|
result.push({ time, text });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.length === 0) {
|
||||||
|
return lines.map(line => ({ time: 0, text: line.trim() }));
|
||||||
|
}
|
||||||
|
|
||||||
return result.sort((a, b) => a.time - b.time);
|
return result.sort((a, b) => a.time - b.time);
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -523,18 +530,28 @@ const formatSliderTooltip = (val) => formatTime(val)
|
|||||||
// 监听 Pinia store 的时间更新
|
// 监听 Pinia store 的时间更新
|
||||||
watch(currentTime, (newVal) => {
|
watch(currentTime, (newVal) => {
|
||||||
if (!isUserSeeking.value) {
|
if (!isUserSeeking.value) {
|
||||||
sliderTime.value = newVal
|
sliderTime.value = newVal;
|
||||||
}
|
}
|
||||||
// 更新歌词
|
// 更新歌词
|
||||||
if (parsedLyric.value.length > 0) {
|
if (parsedLyric.value && parsedLyric.value.length > 0) {
|
||||||
let newIndex = parsedLyric.value.findIndex(line => line.time > newVal) - 1
|
let newIndex = parsedLyric.value.findIndex(l => l.time > newVal);
|
||||||
if (newIndex < 0) newIndex = parsedLyric.value.length - 1
|
|
||||||
|
if (newIndex === -1) {
|
||||||
|
// We are at or after the last lyric line
|
||||||
|
newIndex = parsedLyric.value.length - 1;
|
||||||
|
} else {
|
||||||
|
// The active line is the one before the next line
|
||||||
|
newIndex = newIndex - 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentLyricIndex.value !== newIndex) {
|
if (currentLyricIndex.value !== newIndex) {
|
||||||
currentLyricIndex.value = newIndex
|
currentLyricIndex.value = newIndex;
|
||||||
if (isExpanded.value) scrollToActiveLyric()
|
if (isExpanded.value && newIndex >= 0) {
|
||||||
|
scrollToActiveLyric();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 滚动到当前歌词
|
// 滚动到当前歌词
|
||||||
const scrollToActiveLyric = async () => {
|
const scrollToActiveLyric = async () => {
|
||||||
@@ -577,6 +594,34 @@ watch(() => currentMusic.value?.id, (newId) => {
|
|||||||
if (isExpanded.value) expandedActiveTab.value = 'lyric'
|
if (isExpanded.value) expandedActiveTab.value = 'lyric'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 监听当前播放时间,更新歌词
|
||||||
|
watch(currentTime, (newTime) => {
|
||||||
|
if (!parsedLyric.value || parsedLyric.value.length === 0) return
|
||||||
|
|
||||||
|
let newIndex = -1
|
||||||
|
for (let i = 0; i < parsedLyric.value.length; i++) {
|
||||||
|
if (newTime >= parsedLyric.value[i].time) {
|
||||||
|
newIndex = i
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newIndex !== currentLyricIndex.value) {
|
||||||
|
currentLyricIndex.value = newIndex
|
||||||
|
if (newIndex > -1 && lyricScrollbar.value && lyricLines.value[newIndex]) {
|
||||||
|
const lineEl = lyricLines.value[newIndex]
|
||||||
|
const scrollbarEl = lyricScrollbar.value.wrapRef
|
||||||
|
if (scrollbarEl) {
|
||||||
|
const offsetTop = lineEl.offsetTop
|
||||||
|
const scrollbarHeight = scrollbarEl.clientHeight
|
||||||
|
const targetScrollTop = offsetTop - scrollbarHeight / 2 + lineEl.clientHeight / 2
|
||||||
|
lyricScrollbar.value.setScrollTop(targetScrollTop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user