refactor(lyric): 抽取全屏背景/文字颜色逻辑为 useLyricBackground composable

MusicFull.vue 与 MusicFullMobile.vue 各自持有的 setTextColors /
currentBackground / animationFrame / isDark 合并到共享 composable,
消除两份几乎一致的包装逻辑。Mobile 的 --bg-color 差异通过 writeBgColor
option 注入,行为等价。
This commit is contained in:
alger
2026-04-20 14:48:59 +08:00
parent 7e95ab69be
commit 5ba9e6591a
3 changed files with 89 additions and 105 deletions
@@ -408,12 +408,13 @@ import {
useLyricProgress
} from '@/hooks/MusicHook';
import { useArtist } from '@/hooks/useArtist';
import { useLyricBackground } from '@/hooks/useLyricBackground';
import { usePlayMode } from '@/hooks/usePlayMode';
import { audioService } from '@/services/audioService';
import { usePlayerStore } from '@/store/modules/player';
import { DEFAULT_LYRIC_CONFIG, LyricConfig } from '@/types/lyric';
import { getImgUrl, secondToMinute } from '@/utils';
import { animateGradient, getHoverBackgroundColor, getTextColors } from '@/utils/linearColor';
import { getTextColors } from '@/utils/linearColor';
import { showBottomToast } from '@/utils/shortcutToast';
const { t } = useI18n();
@@ -876,10 +877,10 @@ const handleThumbTouchEnd = (e: TouchEvent) => {
isThumbDragging.value = false;
};
// 背景相关
const currentBackground = ref('');
const animationFrame = ref<number | null>(null);
const isDark = ref(false);
// 背景相关(由 composable 管理)
const { isDark, applyBackground } = useLyricBackground({
writeBgColor: () => playerStore.playMusic.primaryColor || undefined
});
const config = ref<LyricConfig>({ ...DEFAULT_LYRIC_CONFIG });
// 可见歌词计算
@@ -937,49 +938,6 @@ const isVisible = computed({
set: (value) => emit('update:modelValue', value)
});
// 设置文字颜色
const setTextColors = (background: string) => {
if (!background) {
textColors.value = getTextColors();
document.documentElement.style.setProperty('--hover-bg-color', getHoverBackgroundColor(false));
document.documentElement.style.setProperty('--text-color-primary', textColors.value.primary);
document.documentElement.style.setProperty('--text-color-active', textColors.value.active);
document.documentElement.style.setProperty('--bg-color', 'rgba(25, 25, 25, 1)');
return;
}
// 更新文字颜色
textColors.value = getTextColors(background);
isDark.value = textColors.value.active === '#000000';
document.documentElement.style.setProperty(
'--hover-bg-color',
getHoverBackgroundColor(isDark.value)
);
document.documentElement.style.setProperty('--text-color-primary', textColors.value.primary);
document.documentElement.style.setProperty('--text-color-active', textColors.value.active);
// 解析背景颜色用于封面融合
let bgColor = playerStore.playMusic.primaryColor || 'rgba(25, 25, 25, 1)';
document.documentElement.style.setProperty('--bg-color', bgColor);
// 处理背景颜色动画
if (currentBackground.value) {
if (animationFrame.value) {
cancelAnimationFrame(animationFrame.value);
}
const result = animateGradient(currentBackground.value, background, (gradient) => {
currentBackground.value = gradient;
});
if (typeof result === 'number') {
animationFrame.value = result;
}
} else {
currentBackground.value = background;
}
};
const targetBackground = computed(() => {
if (config.value.theme !== 'default') {
return themeMusic[config.value.theme] || props.background;
@@ -992,17 +950,14 @@ watch(
targetBackground,
(newBg) => {
if (newBg) {
setTextColors(newBg);
applyBackground(newBg);
}
},
{ immediate: true }
);
// 组件卸载清理动画
// 组件卸载清理
onBeforeUnmount(() => {
if (animationFrame.value) {
cancelAnimationFrame(animationFrame.value);
}
if (autoScrollTimer.value) {
clearTimeout(autoScrollTimer.value);
}
@@ -1113,7 +1068,7 @@ watch(isVisible, (newVal) => {
if (newVal) {
// 播放器显示时,重新设置背景颜色
if (targetBackground.value) {
setTextColors(targetBackground.value);
applyBackground(targetBackground.value);
}
} else {
showFullLyrics.value = false;