mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-23 23:57:22 +08:00
✨ feat: 优化歌词背景色 加载问题
This commit is contained in:
@@ -20,7 +20,7 @@ function createWindow() {
|
|||||||
win.setMinimumSize(1200, 780);
|
win.setMinimumSize(1200, 780);
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
win.webContents.openDevTools({ mode: 'detach' });
|
win.webContents.openDevTools({ mode: 'detach' });
|
||||||
win.loadURL('http://localhost:4678/');
|
win.loadURL('http://localhost:7788/');
|
||||||
} else {
|
} else {
|
||||||
win.loadURL(`file://${__dirname}/dist/index.html`);
|
win.loadURL(`file://${__dirname}/dist/index.html`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="song-item" :class="{ 'song-mini': mini }">
|
<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">
|
||||||
<div class="song-item-content-title">
|
<div class="song-item-content-title">
|
||||||
<n-ellipsis class="text-ellipsis" line-clamp="1">{{ item.name }}</n-ellipsis>
|
<n-ellipsis class="text-ellipsis" line-clamp="1">{{ item.name }}</n-ellipsis>
|
||||||
@@ -30,10 +40,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { useTemplateRef } from 'vue';
|
||||||
import { useStore } from 'vuex';
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
import type { SongResult } from '@/type/music';
|
import type { SongResult } from '@/type/music';
|
||||||
import { getImgUrl } from '@/utils';
|
import { getImgUrl } from '@/utils';
|
||||||
|
import { getImageBackground } from '@/utils/linearColor';
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
@@ -60,6 +72,14 @@ const isPlaying = computed(() => {
|
|||||||
|
|
||||||
const emits = defineEmits(['play']);
|
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) => {
|
const playMusicEvent = async (item: SongResult) => {
|
||||||
if (playMusic.value.id === item.id) {
|
if (playMusic.value.id === item.id) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-page">
|
<div class="layout-page">
|
||||||
<div class="layout-main">
|
<div class="layout-main" :style="{ background: backgroundColor }">
|
||||||
<title-bar v-if="isElectron" />
|
<title-bar v-if="isElectron" />
|
||||||
<div class="layout-main-page" :class="isElectron ? '' : 'pt-6'">
|
<div class="layout-main-page" :class="isElectron ? '' : 'pt-6'">
|
||||||
<!-- 侧边菜单栏 -->
|
<!-- 侧边菜单栏 -->
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<!-- 搜索栏 -->
|
<!-- 搜索栏 -->
|
||||||
<search-bar />
|
<search-bar />
|
||||||
<!-- 主页面路由 -->
|
<!-- 主页面路由 -->
|
||||||
<div class="main-content bg-black" :native-scrollbar="false">
|
<div class="main-content" :native-scrollbar="false">
|
||||||
<n-message-provider>
|
<n-message-provider>
|
||||||
<router-view
|
<router-view
|
||||||
v-slot="{ Component }"
|
v-slot="{ Component }"
|
||||||
@@ -70,6 +70,18 @@ const audio = {
|
|||||||
value: document.querySelector('#MusicAudio') as HTMLAudioElement,
|
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(() => {
|
onMounted(() => {
|
||||||
// 监听音乐是否播放
|
// 监听音乐是否播放
|
||||||
watch(
|
watch(
|
||||||
@@ -118,11 +130,11 @@ const playMusicEvent = async () => {
|
|||||||
.layout-page {
|
.layout-page {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
@apply flex justify-center items-center overflow-hidden;
|
@apply flex justify-center items-center overflow-hidden bg-black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-main {
|
.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%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
.drawer-back {
|
.drawer-back {
|
||||||
@apply absolute bg-cover bg-center;
|
@apply absolute bg-cover bg-center;
|
||||||
filter: brightness(80%);
|
// filter: brightness(80%);
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
width: 200%;
|
width: 200%;
|
||||||
height: 200%;
|
height: 200%;
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ watch(
|
|||||||
() => store.state.playMusic,
|
() => store.state.playMusic,
|
||||||
async () => {
|
async () => {
|
||||||
loadLrc(playMusic.value.id);
|
loadLrc(playMusic.value.id);
|
||||||
background.value = await getImageLinearBackground(getImgUrl(playMusic.value?.picUrl, '300y300'));
|
background.value = playMusic.value.backgroundColor as string;
|
||||||
},
|
},
|
||||||
{ immediate: true, deep: true },
|
{ immediate: true, deep: true },
|
||||||
);
|
);
|
||||||
|
|||||||
+21
-11
@@ -4,7 +4,8 @@ import { getMusicUrl, getParsingMusicUrl } from '@/api/music';
|
|||||||
import { useMusicHistory } from '@/hooks/MusicHistoryHook';
|
import { useMusicHistory } from '@/hooks/MusicHistoryHook';
|
||||||
import homeRouter from '@/router/home';
|
import homeRouter from '@/router/home';
|
||||||
import type { SongResult } from '@/type/music';
|
import type { SongResult } from '@/type/music';
|
||||||
import { getMusicProxyUrl } from '@/utils';
|
import { getImgUrl, getMusicProxyUrl } from '@/utils';
|
||||||
|
import { getImageLinearBackground } from '@/utils/linearColor';
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
menus: any[];
|
menus: any[];
|
||||||
@@ -47,12 +48,7 @@ const mutations = {
|
|||||||
state.menus = menus;
|
state.menus = menus;
|
||||||
},
|
},
|
||||||
async setPlay(state: State, playMusic: SongResult) {
|
async setPlay(state: State, playMusic: SongResult) {
|
||||||
state.playMusic = { ...playMusic, playLoading: true };
|
await getSongDetail(state, playMusic);
|
||||||
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);
|
|
||||||
},
|
},
|
||||||
setIsPlay(state: State, isPlay: boolean) {
|
setIsPlay(state: State, isPlay: boolean) {
|
||||||
state.isPlay = isPlay;
|
state.isPlay = isPlay;
|
||||||
@@ -69,16 +65,16 @@ const mutations = {
|
|||||||
state.play = true;
|
state.play = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.playListIndex = (state.playListIndex + 1) % state.playList.length;
|
const playListIndex = (state.playListIndex + 1) % state.playList.length;
|
||||||
await updatePlayMusic(state);
|
await getSongDetail(state, state.playList[playListIndex]);
|
||||||
},
|
},
|
||||||
async prevPlay(state: State) {
|
async prevPlay(state: State) {
|
||||||
if (state.playList.length === 0) {
|
if (state.playList.length === 0) {
|
||||||
state.play = true;
|
state.play = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.playListIndex = (state.playListIndex - 1 + state.playList.length) % state.playList.length;
|
const playListIndex = (state.playListIndex - 1 + state.playList.length) % state.playList.length;
|
||||||
await updatePlayMusic(state);
|
await getSongDetail(state, state.playList[playListIndex]);
|
||||||
},
|
},
|
||||||
async setSetData(state: State, setData: any) {
|
async setSetData(state: State, setData: any) {
|
||||||
state.setData = setData;
|
state.setData = setData;
|
||||||
@@ -108,6 +104,20 @@ const updatePlayMusic = async (state: State) => {
|
|||||||
musicHistory.addMusic(state.playMusic);
|
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({
|
const store = createStore({
|
||||||
state,
|
state,
|
||||||
mutations,
|
mutations,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export interface SongResult {
|
|||||||
playLoading?: boolean;
|
playLoading?: boolean;
|
||||||
ar?: Artist[];
|
ar?: Artist[];
|
||||||
al?: Album;
|
al?: Album;
|
||||||
|
backgroundColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Song {
|
export interface Song {
|
||||||
|
|||||||
@@ -1,6 +1,40 @@
|
|||||||
export const getImageLinearBackground = async (imageSrc: string): Promise<string> => {
|
export const getImageLinearBackground = async (imageSrc: string): Promise<string> => {
|
||||||
const primaryColor = await getImagePrimaryColor(imageSrc);
|
try {
|
||||||
return generateGradientBackground(primaryColor);
|
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> => {
|
const getImagePrimaryColor = (imageSrc: string): Promise<string> => {
|
||||||
@@ -49,7 +83,7 @@ const generateGradientBackground = (color: string): string => {
|
|||||||
const [h, s, l] = rgbToHsl(r, g, b);
|
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 darkL = Math.max(l - 0.5, 0.05);
|
||||||
const midL = (lightL + darkL) / 2;
|
const midL = (lightL + darkL) / 2;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user