feat: 优化歌词背景色 加载问题

This commit is contained in:
alger
2024-09-18 15:11:20 +08:00
parent 6dc14ec51b
commit eb2ea1981d
8 changed files with 99 additions and 22 deletions

2
app.js
View File

@@ -20,7 +20,7 @@ function createWindow() {
win.setMinimumSize(1200, 780);
if (process.env.NODE_ENV === 'development') {
win.webContents.openDevTools({ mode: 'detach' });
win.loadURL('http://localhost:4678/');
win.loadURL('http://localhost:7788/');
} else {
win.loadURL(`file://${__dirname}/dist/index.html`);
}

View File

@@ -1,6 +1,16 @@
<template>
<div class="song-item" :class="{ 'song-mini': mini }">
<n-image v-if="item.picUrl" :src="getImgUrl(item.picUrl, '40y40')" class="song-item-img" lazy preview-disabled />
<n-image
v-if="item.picUrl"
ref="songImg"
:src="getImgUrl(item.picUrl, '40y40')"
class="song-item-img"
preview-disabled
:img-props="{
crossorigin: 'anonymous',
}"
@load="imageLoad"
/>
<div class="song-item-content">
<div class="song-item-content-title">
<n-ellipsis class="text-ellipsis" line-clamp="1">{{ item.name }}</n-ellipsis>
@@ -30,10 +40,12 @@
</template>
<script lang="ts" setup>
import { useTemplateRef } from 'vue';
import { useStore } from 'vuex';
import type { SongResult } from '@/type/music';
import { getImgUrl } from '@/utils';
import { getImageBackground } from '@/utils/linearColor';
const props = withDefaults(
defineProps<{
@@ -60,6 +72,14 @@ const isPlaying = computed(() => {
const emits = defineEmits(['play']);
const songImageRef = useTemplateRef('songImg');
const imageLoad = async () => {
const background = await getImageBackground((songImageRef.value as any).imageRef as unknown as HTMLImageElement);
// eslint-disable-next-line vue/no-mutating-props
props.item.backgroundColor = background;
};
// 播放音乐 设置音乐详情 打开音乐底栏
const playMusicEvent = async (item: SongResult) => {
if (playMusic.value.id === item.id) {

View File

@@ -1,6 +1,6 @@
<template>
<div class="layout-page">
<div class="layout-main">
<div class="layout-main" :style="{ background: backgroundColor }">
<title-bar v-if="isElectron" />
<div class="layout-main-page" :class="isElectron ? '' : 'pt-6'">
<!-- 侧边菜单栏 -->
@@ -9,7 +9,7 @@
<!-- 搜索栏 -->
<search-bar />
<!-- 主页面路由 -->
<div class="main-content bg-black" :native-scrollbar="false">
<div class="main-content" :native-scrollbar="false">
<n-message-provider>
<router-view
v-slot="{ Component }"
@@ -70,6 +70,18 @@ const audio = {
value: document.querySelector('#MusicAudio') as HTMLAudioElement,
};
const backgroundColor = ref('#000');
// watch(
// () => store.state.playMusic,
// () => {
// backgroundColor.value = store.state.playMusic.backgroundColor;
// console.log('backgroundColor.value', backgroundColor.value);
// },
// {
// immediate: true,
// deep: true,
// },
// );
onMounted(() => {
// 监听音乐是否播放
watch(
@@ -118,11 +130,11 @@ const playMusicEvent = async () => {
.layout-page {
width: 100vw;
height: 100vh;
@apply flex justify-center items-center overflow-hidden;
@apply flex justify-center items-center overflow-hidden bg-black;
}
.layout-main {
@apply bg-black text-white shadow-xl flex flex-col relative;
@apply text-white shadow-xl flex flex-col relative transition-all;
height: 100%;
width: 100%;
overflow: hidden;

View File

@@ -112,7 +112,7 @@ defineExpose({
}
.drawer-back {
@apply absolute bg-cover bg-center;
filter: brightness(80%);
// filter: brightness(80%);
z-index: -1;
width: 200%;
height: 200%;

View File

@@ -127,7 +127,7 @@ watch(
() => store.state.playMusic,
async () => {
loadLrc(playMusic.value.id);
background.value = await getImageLinearBackground(getImgUrl(playMusic.value?.picUrl, '300y300'));
background.value = playMusic.value.backgroundColor as string;
},
{ immediate: true, deep: true },
);

View File

@@ -4,7 +4,8 @@ import { getMusicUrl, getParsingMusicUrl } from '@/api/music';
import { useMusicHistory } from '@/hooks/MusicHistoryHook';
import homeRouter from '@/router/home';
import type { SongResult } from '@/type/music';
import { getMusicProxyUrl } from '@/utils';
import { getImgUrl, getMusicProxyUrl } from '@/utils';
import { getImageLinearBackground } from '@/utils/linearColor';
interface State {
menus: any[];
@@ -47,12 +48,7 @@ const mutations = {
state.menus = menus;
},
async setPlay(state: State, playMusic: SongResult) {
state.playMusic = { ...playMusic, playLoading: true };
state.playMusicUrl = await getSongUrl(playMusic.id);
state.play = true;
musicHistory.addMusic(playMusic);
state.playMusic.playLoading = false;
state.playListIndex = state.playList.findIndex((item) => item.id === playMusic.id);
await getSongDetail(state, playMusic);
},
setIsPlay(state: State, isPlay: boolean) {
state.isPlay = isPlay;
@@ -69,16 +65,16 @@ const mutations = {
state.play = true;
return;
}
state.playListIndex = (state.playListIndex + 1) % state.playList.length;
await updatePlayMusic(state);
const playListIndex = (state.playListIndex + 1) % state.playList.length;
await getSongDetail(state, state.playList[playListIndex]);
},
async prevPlay(state: State) {
if (state.playList.length === 0) {
state.play = true;
return;
}
state.playListIndex = (state.playListIndex - 1 + state.playList.length) % state.playList.length;
await updatePlayMusic(state);
const playListIndex = (state.playListIndex - 1 + state.playList.length) % state.playList.length;
await getSongDetail(state, state.playList[playListIndex]);
},
async setSetData(state: State, setData: any) {
state.setData = setData;
@@ -108,6 +104,20 @@ const updatePlayMusic = async (state: State) => {
musicHistory.addMusic(state.playMusic);
};
const getSongDetail = async (state: State, playMusic: SongResult) => {
state.playMusic.playLoading = true;
state.playMusicUrl = await getSongUrl(playMusic.id);
const backgroundColor = playMusic.backgroundColor
? playMusic.backgroundColor
: await getImageLinearBackground(getImgUrl(playMusic?.picUrl, '30y30'));
state.playMusic = { ...playMusic, backgroundColor };
// state.playMusic = { ...playMusic };
state.play = true;
musicHistory.addMusic(playMusic);
state.playListIndex = state.playList.findIndex((item) => item.id === playMusic.id);
state.playMusic.playLoading = false;
};
const store = createStore({
state,
mutations,

View File

@@ -18,6 +18,7 @@ export interface SongResult {
playLoading?: boolean;
ar?: Artist[];
al?: Album;
backgroundColor?: string;
}
export interface Song {

View File

@@ -1,6 +1,40 @@
export const getImageLinearBackground = async (imageSrc: string): Promise<string> => {
const primaryColor = await getImagePrimaryColor(imageSrc);
return generateGradientBackground(primaryColor);
try {
const primaryColor = await getImagePrimaryColor(imageSrc);
return generateGradientBackground(primaryColor);
} catch (error) {
console.error('error', error);
return '';
}
};
export const getImageBackground = async (img: HTMLImageElement): Promise<string> => {
try {
const primaryColor = await getImageColor(img);
return generateGradientBackground(primaryColor);
} catch (error) {
console.error('error', error);
return '';
}
};
const getImageColor = (img: HTMLImageElement): Promise<string> => {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
reject(new Error('无法获取canvas上下文'));
return;
}
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const color = getAverageColor(imageData.data);
resolve(`rgb(${color.join(',')})`);
});
};
const getImagePrimaryColor = (imageSrc: string): Promise<string> => {
@@ -49,7 +83,7 @@ const generateGradientBackground = (color: string): string => {
const [h, s, l] = rgbToHsl(r, g, b);
// 增加亮度和暗度的差异
const lightL = Math.min(l + 0.8, 0.95);
const lightL = Math.min(l + 0.5, 0.95);
const darkL = Math.max(l - 0.5, 0.05);
const midL = (lightL + darkL) / 2;