fix: update language attribute in HTML and adjust script source path for consistency
refactor(ScrollingLyrics): simplify markup and improve readability of lyrics rendering logic
This commit is contained in:
parent
5a200edd11
commit
d8d1284c56
19
src/App.vue
19
src/App.vue
|
@ -20,33 +20,40 @@ const route = useRoute()
|
|||
})()">
|
||||
<li>
|
||||
<RouterLink to="/">
|
||||
<span class="text-4xl" :class="route.path === '/' ? 'font-semibold text-white' : 'text-white/50 hover:text-white/80'">浏览</span>
|
||||
<span class="text-4xl"
|
||||
:class="route.path === '/' ? 'font-semibold text-white' : 'text-white/50 hover:text-white/80'">浏览</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/lucky" :class="route.path === '/lucky'? 'font-semibold text-white' : 'text-white/50 hover:text-white/80'">
|
||||
<RouterLink to="/lucky"
|
||||
:class="route.path === '/lucky' ? 'font-semibold text-white' : 'text-white/50 hover:text-white/80'">
|
||||
<span class="text-4xl">手气不错</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/library" :class="route.path === '/library'? 'font-semibold text-white' : 'text-white/50 hover:text-white/80'">
|
||||
<RouterLink to="/library"
|
||||
:class="route.path === '/library' ? 'font-semibold text-white' : 'text-white/50 hover:text-white/80'">
|
||||
<span class="text-4xl">收藏库</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div v-else>
|
||||
<button class="text-white w-9 h-9 bg-white/5 border border-[#ffffff39] rounded-full text-center backdrop-blur-3xl flex justify-center items-center" @click="$router.back()">
|
||||
<button
|
||||
class="text-white w-9 h-9 bg-white/5 border border-[#ffffff39] rounded-full text-center backdrop-blur-3xl flex justify-center items-center"
|
||||
@click="$router.back()">
|
||||
<LeftArrowIcon :size="4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<button class="text-white w-9 h-9 bg-neutral-800/80 border border-[#ffffff39] rounded-full text-center backdrop-blur-3xl flex justify-center items-center">
|
||||
<button
|
||||
class="text-white w-9 h-9 bg-neutral-800/80 border border-[#ffffff39] rounded-full text-center backdrop-blur-3xl flex justify-center items-center">
|
||||
<SearchIcon :size="4" />
|
||||
</button>
|
||||
|
||||
<button class="text-white w-9 h-9 bg-neutral-800/80 border border-[#ffffff39] rounded-full text-center backdrop-blur-3xl flex justify-center items-center">
|
||||
<button
|
||||
class="text-white w-9 h-9 bg-neutral-800/80 border border-[#ffffff39] rounded-full text-center backdrop-blur-3xl flex justify-center items-center">
|
||||
<CorgIcon :size="4" />
|
||||
</button>
|
||||
|
||||
|
|
|
@ -1,51 +1,36 @@
|
|||
<template>
|
||||
<div
|
||||
class="relative overflow-hidden h-full w-[40rem]"
|
||||
ref="lyricsContainer"
|
||||
@wheel="handleWheel"
|
||||
>
|
||||
<div class="relative overflow-hidden h-full w-[40rem]" ref="lyricsContainer" @wheel="handleWheel">
|
||||
<!-- 歌词滚动区域 -->
|
||||
<div
|
||||
class="relative"
|
||||
ref="lyricsWrapper"
|
||||
>
|
||||
<div class="relative" ref="lyricsWrapper">
|
||||
<!-- 顶部填充 -->
|
||||
<div class="h-1/2 pointer-events-none"></div>
|
||||
|
||||
<div
|
||||
v-for="(line, index) in parsedLyrics"
|
||||
:key="index"
|
||||
:ref="el => setLineRef(el as HTMLElement, index)"
|
||||
<div v-for="(line, index) in parsedLyrics" :key="index" :ref="el => setLineRef(el as HTMLElement, index)"
|
||||
class="py-8 px-16 cursor-pointer transition-all duration-300 hover:scale-105"
|
||||
@click="handleLineClick(line, index)"
|
||||
>
|
||||
@click="handleLineClick(line, index)">
|
||||
<div v-if="line.type === 'lyric'" class="relative">
|
||||
<!-- 背景模糊文字 -->
|
||||
<div
|
||||
class="text-3xl font-bold transition-all duration-500"
|
||||
:class="[
|
||||
<div class="text-3xl font-bold transition-all duration-500" :class="[
|
||||
currentLineIndex === index ? 'text-black/80 blur-xl' : 'text-black/20 blur-2xl'
|
||||
]"
|
||||
>
|
||||
]">
|
||||
{{ line.text }}
|
||||
</div>
|
||||
<!-- 前景清晰文字 -->
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full text-3xl font-bold transition-all duration-500"
|
||||
:class="[
|
||||
<div class="absolute top-0 left-0 w-full text-3xl font-bold transition-all duration-500" :class="[
|
||||
currentLineIndex === index
|
||||
? 'text-white scale-110'
|
||||
: index < currentLineIndex
|
||||
? userScrolling ? 'text-white/60' : 'text-white/60 blur-sm'
|
||||
: userScrolling ? 'text-white/40' : 'text-white/40 blur-sm'
|
||||
]"
|
||||
>
|
||||
]">
|
||||
{{ line.text }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="line.type === 'gap'" class="flex justify-center items-center py-4">
|
||||
<div class="w-16 h-px rounded-full"></div>
|
||||
<div v-else-if="line.type === 'gap'" class="flex items-center gap-2">
|
||||
<div v-for="dot in 3" :key="dot" class="bg-white rounded-full"
|
||||
:class="currentLineIndex === index ? 'w-4 h-4' : ''"
|
||||
:style="{ opacity: getGapDotOpacities(line)[dot - 1] }" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -54,49 +39,35 @@
|
|||
</div>
|
||||
|
||||
<!-- 歌词控制面板 -->
|
||||
<div
|
||||
class="absolute top-4 right-4 flex gap-2 opacity-0 transition-opacity duration-300 hover:opacity-100"
|
||||
ref="controlPanel"
|
||||
>
|
||||
<button
|
||||
@click="toggleAutoScroll"
|
||||
<div class="absolute top-4 right-4 flex gap-2 opacity-0 transition-opacity duration-300 hover:opacity-100"
|
||||
ref="controlPanel">
|
||||
<button @click="toggleAutoScroll"
|
||||
class="px-3 py-1 rounded-full text-xs backdrop-blur-md text-white/80 hover:text-white transition-all duration-200"
|
||||
:class="[
|
||||
autoScroll
|
||||
? 'bg-white/20 shadow-lg'
|
||||
: 'bg-black/20 hover:bg-black/30'
|
||||
]"
|
||||
>
|
||||
]">
|
||||
{{ autoScroll ? '自动' : '手动' }}
|
||||
</button>
|
||||
<button
|
||||
@click="resetScroll"
|
||||
class="px-3 py-1 rounded-full text-xs bg-black/20 backdrop-blur-md text-white/80 hover:bg-black/30 hover:text-white transition-all duration-200"
|
||||
>
|
||||
<button @click="resetScroll"
|
||||
class="px-3 py-1 rounded-full text-xs bg-black/20 backdrop-blur-md text-white/80 hover:bg-black/30 hover:text-white transition-all duration-200">
|
||||
重置
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 滚动指示器 -->
|
||||
<div
|
||||
class="absolute right-2 top-1/4 bottom-1/4 w-1 bg-white/10 rounded-full overflow-hidden"
|
||||
v-if="parsedLyrics.length > 5"
|
||||
>
|
||||
<div
|
||||
class="w-full bg-white/40 rounded-full transition-all duration-300"
|
||||
:style="{
|
||||
<div class="absolute right-2 top-1/4 bottom-1/4 w-1 bg-white/10 rounded-full overflow-hidden"
|
||||
v-if="parsedLyrics.length > 5">
|
||||
<div class="w-full bg-white/40 rounded-full transition-all duration-300" :style="{
|
||||
height: scrollIndicatorHeight + '%',
|
||||
transform: `translateY(${scrollIndicatorPosition}px)`
|
||||
}"
|
||||
></div>
|
||||
}"></div>
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div
|
||||
v-if="loading"
|
||||
class="absolute inset-0 flex items-center justify-center backdrop-blur-sm"
|
||||
ref="loadingIndicator"
|
||||
>
|
||||
<div v-if="loading" class="absolute inset-0 flex items-center justify-center backdrop-blur-sm"
|
||||
ref="loadingIndicator">
|
||||
<div class="flex items-center gap-3 px-6 py-3 rounded-full bg-black/20 backdrop-blur-md">
|
||||
<div class="w-4 h-4 border-2 border-white/60 border-t-white rounded-full animate-spin"></div>
|
||||
<div class="text-white/80 text-sm font-medium">加载歌词中...</div>
|
||||
|
@ -104,11 +75,8 @@
|
|||
</div>
|
||||
|
||||
<!-- 无歌词状态 -->
|
||||
<div
|
||||
v-if="!loading && parsedLyrics.length === 0"
|
||||
class="absolute inset-0 flex items-center justify-center"
|
||||
ref="noLyricsIndicator"
|
||||
>
|
||||
<div v-if="!loading && parsedLyrics.length === 0" class="absolute inset-0 flex items-center justify-center"
|
||||
ref="noLyricsIndicator">
|
||||
<div class="text-center">
|
||||
<div class="text-white/40 text-lg font-medium mb-2">暂无歌词</div>
|
||||
<div class="text-white/30 text-sm">享受纯音乐的美妙</div>
|
||||
|
@ -487,6 +455,24 @@ function resetScroll() {
|
|||
}
|
||||
}
|
||||
|
||||
// gap 圆点透明度计算
|
||||
function getGapDotOpacities(line: GapLine) {
|
||||
// 获取 gap 的持续时间
|
||||
const duration = line.duration ?? 0
|
||||
if (duration <= 0) return [0.3, 0.3, 0.3]
|
||||
// 当前播放时间
|
||||
const now = playQueueStore.currentTime
|
||||
// gap 起止时间
|
||||
const start = line.time
|
||||
// 计算进度
|
||||
let progress = (now - start) / duration
|
||||
progress = Math.max(0, Math.min(1, progress))
|
||||
// 每个圆点的阈值
|
||||
const thresholds = [1 / 4, 2 / 4, 3 / 4]
|
||||
// 透明度从 0.3 到 1
|
||||
return thresholds.map(t => progress >= t ? 1 : progress >= t - 1 / 3 ? 0.6 : 0.3)
|
||||
}
|
||||
|
||||
// 监听播放时间变化
|
||||
watch(() => playQueueStore.currentTime, (time) => {
|
||||
const newIndex = findCurrentLineIndex(time)
|
||||
|
|
Loading…
Reference in New Issue
Block a user