feat: 通过 NeteaseMiniPlayer 支持播放来自网易云音乐的音乐

This commit is contained in:
2025-12-07 16:36:55 +08:00
parent 66d7c9cb3c
commit 2cdd81e74b
9 changed files with 1775 additions and 2 deletions

View File

@@ -21,6 +21,8 @@
<Transition name="fade-down">
<FooterSection v-if="!hideComponents" :contact="contact" key="footer" />
</Transition>
<!-- 音乐播放器 -->
<MusicPlayer />
</div>
</template>
@@ -28,6 +30,7 @@
import { onMounted, computed, ref } from "vue";
import PageSwitcher from "./components/PageSwitcher.vue";
import FooterSection from "./components/FooterSection.vue";
import MusicPlayer from "./components/MusicPlayer.vue";
import siteConfig from "./config/siteConfig";
const contact = siteConfig.footer;
@@ -53,7 +56,7 @@ const getBackgroundImage = () => {
if (!image) return undefined;
return image.startsWith("http") ? image : `/public/${image}`;
return image.startsWith("http") ? image : `/${image}`;
};
const backgroundStyle = computed(() => {

View File

@@ -0,0 +1,30 @@
<template>
<div
v-if="music.enable && (music.playlistId || music.songId)"
class="netease-mini-player"
:data-playlist-id="music.mode === 'floating' ? music.playlistId : undefined"
:data-song-id="music.mode === 'embed' ? music.songId : undefined"
:data-embed="music.mode === 'embed'"
:data-position="music.position"
:data-lyric="music.lyric"
:data-theme="music.theme"
:data-autoplay="music.autoplay"
:data-default-minimized="music.defaultMinimized"
></div>
</template>
<script setup lang="ts">
import siteConfig from "../config/siteConfig";
const music = siteConfig.music;
</script>
<!-- <style scoped>
/* 音乐播放器样式由 NeteaseMiniPlayer 提供 */
/* 使用 display: contents 使外层容器不占用空间 */
/* 确保播放器浮动定位,不影响页面布局 */
:deep(.netease-mini-player) {
position: fixed !important;
z-index: 999 !important;
}
</style> -->

View File

@@ -47,6 +47,26 @@ const siteConfig = {
},
},
music: {
enable: true,
// 浮动模式播放器(推荐)- 用于播放网易云歌单
mode: "floating", // "floating" 或 "embed"
// 歌单ID从网易云音乐链接获取如 https://music.163.com/#/playlist?id=14273792576
playlistId: "14366453940", // 例如: "14273792576"
// 歌曲ID仅在嵌入模式下使用
songId: undefined, // 例如: "554242291"
// 播放器位置(浮动模式): "bottom-left" | "bottom-right" | "top-left" | "top-right"
position: "bottom-left",
// 是否显示歌词
lyric: true,
// 主题: "light" | "dark" | "auto"
theme: "dark",
// 是否自动播放
autoplay: false,
// 是否默认以黑胶唱片状态启动(仅浮动模式)
defaultMinimized: true,
},
umami: {
enable: true,
url: "https://cloud.umami.is/script.js",

View File

@@ -12,4 +12,5 @@ if (process.env.NODE_ENV !== "development") {
app.use(VueUmamiPlugin({ websiteID: siteConfig.umami.websiteId, scriptSrc: siteConfig.umami.url, router }));
}
}
app.use(router).mount("#app");

View File

@@ -1,3 +1,7 @@
html {
height: 100%;
}
:root {
color-scheme: light dark;
font-family: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
@@ -7,7 +11,7 @@
body {
margin: 0;
min-height: 100vh;
min-height: 100%;
background: radial-gradient(circle at 20% 20%, #1b2b4b, #0f1629);
}
@@ -90,3 +94,98 @@ p {
text-align: center;
margin-top: 8px;
}
/* Ensure the Netease mini player doesn't occupy page layout space
and stays fixed above content. Use !important to override
styles injected by third-party scripts. */
.netease-mini-player {
position: fixed !important;
bottom: 20px !important;
left: 20px !important;
right: auto !important;
/* do not force width here — let the player's own minimized/expanded
styles control sizing. Only constrain max width as a safety net. */
max-width: calc(100% - 40px) !important;
z-index: 9999 !important;
margin: 0 !important;
transform: none !important;
}
/* If the player injects a full-width bar, make sure it won't
push page content by forcing it out of the normal flow. */
.netease-mini-player > * {
box-sizing: border-box;
}
/* Defensive: hide any accidental full-width injected container from the player
that might occupy vertical space. This targets common helper classes used
by the player script. */
.netease-mini-player-embed,
.nmpv2-player,
.nmpv2-root {
position: fixed !important;
bottom: 20px !important;
left: 20px !important;
right: auto !important;
z-index: 9999 !important;
}
/* Fix: prevent playlist dropdown from increasing document height
by forcing the playlist container to be fixed and clipped to viewport. */
.netease-mini-player[data-position="bottom-left"] .playlist-container,
.netease-mini-player[data-position="bottom-right"] .playlist-container {
position: fixed !important;
bottom: calc(20px + 80px) !important;
left: 20px !important;
right: auto !important;
width: 290px !important;
max-height: 50vh !important;
overflow: auto !important;
z-index: 10001 !important;
}
.netease-mini-player[data-position="top-left"] .playlist-container,
.netease-mini-player[data-position="top-right"] .playlist-container {
position: fixed !important;
top: calc(20px + 80px) !important;
left: 20px !important;
right: auto !important;
width: 290px !important;
max-height: 50vh !important;
overflow: auto !important;
z-index: 10001 !important;
}
/* If player is docked to the right, align playlist to right edge */
.netease-mini-player[data-position="bottom-right"] .playlist-container,
.netease-mini-player[data-position="top-right"] .playlist-container {
left: auto !important;
right: 20px !important;
}
/* Ensure minimized player displays as a circle and its album cover fits */
.netease-mini-player.minimized {
width: 80px !important;
height: 80px !important;
border-radius: 50% !important;
padding: 0 !important;
overflow: hidden !important;
box-shadow: none !important;
}
.netease-mini-player.minimized .album-cover-container {
width: 100% !important;
height: 100% !important;
position: absolute !important;
top: 0 !important;
left: 0 !important;
border-radius: 50% !important;
overflow: hidden !important;
}
.netease-mini-player.minimized .album-cover {
width: 100% !important;
height: 100% !important;
object-fit: cover !important;
border-radius: 50% !important;
}