mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-05-17 18:47:29 +08:00
refactor(lyric): 抽取全屏背景/文字颜色逻辑为 useLyricBackground composable
MusicFull.vue 与 MusicFullMobile.vue 各自持有的 setTextColors / currentBackground / animationFrame / isDark 合并到共享 composable, 消除两份几乎一致的包装逻辑。Mobile 的 --bg-color 差异通过 writeBgColor option 注入,行为等价。
This commit is contained in:
@@ -202,19 +202,18 @@ import {
|
|||||||
useLyricProgress
|
useLyricProgress
|
||||||
} from '@/hooks/MusicHook';
|
} from '@/hooks/MusicHook';
|
||||||
import { useArtist } from '@/hooks/useArtist';
|
import { useArtist } from '@/hooks/useArtist';
|
||||||
|
import { useLyricBackground } from '@/hooks/useLyricBackground';
|
||||||
import { usePlayerStore } from '@/store/modules/player';
|
import { usePlayerStore } from '@/store/modules/player';
|
||||||
import { useSettingsStore } from '@/store/modules/settings';
|
import { useSettingsStore } from '@/store/modules/settings';
|
||||||
import { DEFAULT_LYRIC_CONFIG, LyricConfig } from '@/types/lyric';
|
import { DEFAULT_LYRIC_CONFIG, LyricConfig } from '@/types/lyric';
|
||||||
import { getImgUrl, isMobile } from '@/utils';
|
import { getImgUrl, isMobile } from '@/utils';
|
||||||
import { animateGradient, getHoverBackgroundColor, getTextColors } from '@/utils/linearColor';
|
import { getTextColors } from '@/utils/linearColor';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
// 定义 refs
|
// 定义 refs
|
||||||
const lrcSider = ref<any>(null);
|
const lrcSider = ref<any>(null);
|
||||||
const isMouse = ref(false);
|
const isMouse = ref(false);
|
||||||
const currentBackground = ref('');
|
const { currentBackground, applyBackground } = useLyricBackground();
|
||||||
const animationFrame = ref<number | null>(null);
|
|
||||||
const isDark = ref(false);
|
|
||||||
|
|
||||||
// 计算自定义背景样式
|
// 计算自定义背景样式
|
||||||
const customBackgroundStyle = computed(() => {
|
const customBackgroundStyle = computed(() => {
|
||||||
@@ -381,42 +380,6 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
// 处理背景颜色动画
|
|
||||||
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(() => {
|
const targetBackground = computed(() => {
|
||||||
if (config.value.useCustomBackground && customBackgroundStyle.value) {
|
if (config.value.useCustomBackground && customBackgroundStyle.value) {
|
||||||
if (typeof customBackgroundStyle.value === 'string') {
|
if (typeof customBackgroundStyle.value === 'string') {
|
||||||
@@ -434,7 +397,7 @@ watch(
|
|||||||
targetBackground,
|
targetBackground,
|
||||||
(newBg) => {
|
(newBg) => {
|
||||||
if (newBg) {
|
if (newBg) {
|
||||||
setTextColors(newBg);
|
applyBackground(newBg);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
@@ -523,13 +486,6 @@ const getWordStyle = (lineIndex: number, _wordIndex: number, word: any) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 组件卸载时清理动画
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (animationFrame.value) {
|
|
||||||
cancelAnimationFrame(animationFrame.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
const { navigateToArtist } = useArtist();
|
const { navigateToArtist } = useArtist();
|
||||||
@@ -626,9 +582,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 移除滚动监听和全屏状态监听
|
// 移除滚动监听和全屏状态监听
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (animationFrame.value) {
|
|
||||||
cancelAnimationFrame(animationFrame.value);
|
|
||||||
}
|
|
||||||
if (lrcSider.value?.$el) {
|
if (lrcSider.value?.$el) {
|
||||||
lrcSider.value.$el.removeEventListener('scroll', handleScroll);
|
lrcSider.value.$el.removeEventListener('scroll', handleScroll);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -408,12 +408,13 @@ import {
|
|||||||
useLyricProgress
|
useLyricProgress
|
||||||
} from '@/hooks/MusicHook';
|
} from '@/hooks/MusicHook';
|
||||||
import { useArtist } from '@/hooks/useArtist';
|
import { useArtist } from '@/hooks/useArtist';
|
||||||
|
import { useLyricBackground } from '@/hooks/useLyricBackground';
|
||||||
import { usePlayMode } from '@/hooks/usePlayMode';
|
import { usePlayMode } from '@/hooks/usePlayMode';
|
||||||
import { audioService } from '@/services/audioService';
|
import { audioService } from '@/services/audioService';
|
||||||
import { usePlayerStore } from '@/store/modules/player';
|
import { usePlayerStore } from '@/store/modules/player';
|
||||||
import { DEFAULT_LYRIC_CONFIG, LyricConfig } from '@/types/lyric';
|
import { DEFAULT_LYRIC_CONFIG, LyricConfig } from '@/types/lyric';
|
||||||
import { getImgUrl, secondToMinute } from '@/utils';
|
import { getImgUrl, secondToMinute } from '@/utils';
|
||||||
import { animateGradient, getHoverBackgroundColor, getTextColors } from '@/utils/linearColor';
|
import { getTextColors } from '@/utils/linearColor';
|
||||||
import { showBottomToast } from '@/utils/shortcutToast';
|
import { showBottomToast } from '@/utils/shortcutToast';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -876,10 +877,10 @@ const handleThumbTouchEnd = (e: TouchEvent) => {
|
|||||||
isThumbDragging.value = false;
|
isThumbDragging.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 背景相关
|
// 背景相关(由 composable 管理)
|
||||||
const currentBackground = ref('');
|
const { isDark, applyBackground } = useLyricBackground({
|
||||||
const animationFrame = ref<number | null>(null);
|
writeBgColor: () => playerStore.playMusic.primaryColor || undefined
|
||||||
const isDark = ref(false);
|
});
|
||||||
const config = ref<LyricConfig>({ ...DEFAULT_LYRIC_CONFIG });
|
const config = ref<LyricConfig>({ ...DEFAULT_LYRIC_CONFIG });
|
||||||
|
|
||||||
// 可见歌词计算
|
// 可见歌词计算
|
||||||
@@ -937,49 +938,6 @@ const isVisible = computed({
|
|||||||
set: (value) => emit('update:modelValue', value)
|
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(() => {
|
const targetBackground = computed(() => {
|
||||||
if (config.value.theme !== 'default') {
|
if (config.value.theme !== 'default') {
|
||||||
return themeMusic[config.value.theme] || props.background;
|
return themeMusic[config.value.theme] || props.background;
|
||||||
@@ -992,17 +950,14 @@ watch(
|
|||||||
targetBackground,
|
targetBackground,
|
||||||
(newBg) => {
|
(newBg) => {
|
||||||
if (newBg) {
|
if (newBg) {
|
||||||
setTextColors(newBg);
|
applyBackground(newBg);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
// 组件卸载时清理动画
|
// 组件卸载清理
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (animationFrame.value) {
|
|
||||||
cancelAnimationFrame(animationFrame.value);
|
|
||||||
}
|
|
||||||
if (autoScrollTimer.value) {
|
if (autoScrollTimer.value) {
|
||||||
clearTimeout(autoScrollTimer.value);
|
clearTimeout(autoScrollTimer.value);
|
||||||
}
|
}
|
||||||
@@ -1113,7 +1068,7 @@ watch(isVisible, (newVal) => {
|
|||||||
if (newVal) {
|
if (newVal) {
|
||||||
// 播放器显示时,重新设置背景颜色
|
// 播放器显示时,重新设置背景颜色
|
||||||
if (targetBackground.value) {
|
if (targetBackground.value) {
|
||||||
setTextColors(targetBackground.value);
|
applyBackground(targetBackground.value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showFullLyrics.value = false;
|
showFullLyrics.value = false;
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { onBeforeUnmount, ref } from 'vue';
|
||||||
|
|
||||||
|
import { textColors } from '@/hooks/MusicHook';
|
||||||
|
import { animateGradient, getHoverBackgroundColor, getTextColors } from '@/utils/linearColor';
|
||||||
|
|
||||||
|
type UseLyricBackgroundOptions = {
|
||||||
|
/**
|
||||||
|
* 可选:返回需要写入 --bg-color CSS 变量的颜色字符串。
|
||||||
|
* - 不提供:完全不写 --bg-color(桌面全屏场景)
|
||||||
|
* - 提供:有背景分支调用以取值,undefined 时落回 DEFAULT_BG_COLOR;
|
||||||
|
* 空背景分支固定写入 DEFAULT_BG_COLOR(与移动端原有行为一致)
|
||||||
|
*/
|
||||||
|
writeBgColor?: () => string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_BG_COLOR = 'rgba(25, 25, 25, 1)';
|
||||||
|
|
||||||
|
export function useLyricBackground(options: UseLyricBackgroundOptions = {}) {
|
||||||
|
const currentBackground = ref('');
|
||||||
|
const animationFrame = ref<number | null>(null);
|
||||||
|
const isDark = ref(false);
|
||||||
|
|
||||||
|
const { writeBgColor } = options;
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
const applyBackground = (background: string) => {
|
||||||
|
if (!background) {
|
||||||
|
textColors.value = getTextColors();
|
||||||
|
root.style.setProperty('--hover-bg-color', getHoverBackgroundColor(false));
|
||||||
|
root.style.setProperty('--text-color-primary', textColors.value.primary);
|
||||||
|
root.style.setProperty('--text-color-active', textColors.value.active);
|
||||||
|
if (writeBgColor) {
|
||||||
|
root.style.setProperty('--bg-color', DEFAULT_BG_COLOR);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
textColors.value = getTextColors(background);
|
||||||
|
isDark.value = textColors.value.active === '#000000';
|
||||||
|
|
||||||
|
root.style.setProperty('--hover-bg-color', getHoverBackgroundColor(isDark.value));
|
||||||
|
root.style.setProperty('--text-color-primary', textColors.value.primary);
|
||||||
|
root.style.setProperty('--text-color-active', textColors.value.active);
|
||||||
|
|
||||||
|
if (writeBgColor) {
|
||||||
|
const bg = writeBgColor();
|
||||||
|
root.style.setProperty('--bg-color', bg || DEFAULT_BG_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (animationFrame.value) {
|
||||||
|
cancelAnimationFrame(animationFrame.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
isDark,
|
||||||
|
currentBackground,
|
||||||
|
applyBackground
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user