refactor(background): 简化背景功能为静态图片

动态背景切换功能因效果不佳暂时移除。本次重构将背景实现简化为仅支持单张静态图片
This commit is contained in:
Montia37
2025-08-15 05:19:39 +08:00
parent 2e4f2a8a98
commit e74611b947
7 changed files with 29 additions and 99 deletions

View File

@@ -31,7 +31,15 @@
### 配置背景图片 ### 配置背景图片
为获得最佳视觉效果,建议搭配背景图片使用。请在 `Komari 后台 > 设置 > 站点 > 自定义 Body` 处添加以下代码并保存: > 为获得最佳视觉效果,建议搭配背景图片使用。
#### Komari v1.0.5 及以上版本
如果 Komari 版本为 v1.0.5 或更高版本,可直接在 `Komari 后台 > PurCarte设置` 中配置背景图片等主题选项,无需手动添加自定义代码
#### 旧版本配置方法
对于旧版本,请在 `Komari 后台 > 设置 > 站点 > 自定义 Body` 处添加以下代码并保存:
```html ```html
<style> <style>

View File

@@ -18,24 +18,8 @@
"name": "背景图片链接", "name": "背景图片链接",
"type": "string", "type": "string",
"required": false, "required": false,
"default": "https://i.yon.li/w/682f73d97eade.png", "default": "/assets/Moonlit-Scenery.webp",
"help": "多张图片请以英文逗号分隔eg:https://img.com/1.png,https://test.com/2.jpg" "help": "目前仅支持单张背景图片eg: https://test.com/1.png"
},
{
"key": "switchTime",
"name": "切换时间(秒)",
"type": "number",
"required": false,
"default": 10,
"help": "背景图片切换的时间间隔,单位为秒(仅设置多张图片时生效)"
},
{
"key": "transition",
"name": "背景切换过渡效果",
"type": "string",
"required": false,
"default": "background-image 0.8s ease-in-out",
"help": "CSS 过渡效果,用于背景图片切换时的动画效果(仅设置多张图片时生效)"
} }
] ]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -1,99 +1,39 @@
import { useEffect, useState, useMemo } from "react"; import { useEffect, useMemo } from "react";
import { BACKGROUND } from "@/config/default"; import { BACKGROUND } from "@/config/default";
import type { PublicInfo } from "@/types/node.d"; import type { PublicInfo } from "@/types/node.d";
/** /**
* 动态背景组件 * 动态效果不佳,暂时仅使用静态背景
* 根据设定的时间间隔自动切换背景图片
* 并预加载所有图片以提高用户体验
* 支持自定义过渡效果和切换时间
*/ */
interface ThemeSettings { interface ThemeSettings {
backgroundImage?: string; // 逗号分隔的背景图片URL列表 backgroundImage?: string; // 背景图片URL
switchTime?: number; // 背景切换时间间隔(秒)
transition?: string; // CSS过渡效果
} }
interface BackgroundProps { interface BackgroundProps {
publicSettings: PublicInfo; publicSettings: PublicInfo;
} }
function DynamicPseudoBackground({ publicSettings }: BackgroundProps) { function Background({ publicSettings }: BackgroundProps) {
const theme = (publicSettings?.theme_settings as ThemeSettings) || {}; const theme = (publicSettings?.theme_settings as ThemeSettings) || {};
// 使用 useMemo 缓存背景图片列表,避免每次渲染时重新计算 // 使用 useMemo 缓存背景图片列表,避免每次渲染时重新计算
const imageList = useMemo(() => { const imageUrl = useMemo(() => {
return theme.backgroundImage return theme.backgroundImage
? theme.backgroundImage.split(",").map((url) => url.trim()) ? theme.backgroundImage
: [BACKGROUND.backgroundImage]; : BACKGROUND.backgroundImage;
}, [theme.backgroundImage]); }, [theme.backgroundImage]);
// 将切换时间从秒转换为毫秒
const switchTime = useMemo(() => {
return (theme.switchTime || BACKGROUND.switchTime) * 1000;
}, [theme.switchTime]);
const transition = useMemo(() => {
return theme.transition || BACKGROUND.transition;
}, [theme.transition]);
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const currentImageUrl = imageList[currentImageIndex];
// 预加载指定的图片
const preloadImage = (url: string) => {
if (!url) return;
const img = new Image();
img.src = url;
};
// 预加载所有图片,只在组件初始化或图片列表变化时执行一次
useEffect(() => {
// 只有当有多张图片时才设置过渡效果
if (imageList.length > 1) {
document.body.style.setProperty(
"--body-background-transition",
transition
);
// 预加载所有图片以提高用户体验
imageList.forEach((url) => {
preloadImage(url);
});
}
// 组件卸载时清理
return () => {
document.body.style.removeProperty("--body-background-transition");
};
}, [imageList, transition]);
// 背景切换逻辑 // 背景切换逻辑
useEffect(() => { useEffect(() => {
// 当当前图片URL变化时更新CSS变量 // 当当前图片URL变化时更新CSS变量
document.body.style.setProperty( document.body.style.setProperty(
"--body-background-url", "--body-background-url",
`url(${currentImageUrl})` `url(${imageUrl})`
); );
}, [imageUrl]);
// 只有当有多张图片时才设置定时器进行轮换
let intervalId: number | undefined;
if (imageList.length > 1) {
intervalId = window.setInterval(() => {
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % imageList.length);
}, switchTime);
}
// 清理函数,组件卸载或依赖项变化时执行
return () => {
if (intervalId) {
clearInterval(intervalId);
}
};
}, [currentImageUrl, imageList, switchTime]);
// 此组件不渲染任何可见内容 // 此组件不渲染任何可见内容
return null; return null;
} }
export default DynamicPseudoBackground; export default Background;

View File

@@ -1,5 +1,5 @@
export const BACKGROUND = { export const BACKGROUND = {
backgroundImage: "https://i.yon.li/w/682f73d97eade.png", backgroundImage: "",
switchTime: 10, // 10 seconds // switchTime: 10, // 10 seconds
transition: "background-image 0.8s ease-in-out", // CSS transition for background change // transition: "background-image 0.8s ease-in-out", // CSS transition for background change
}; };

View File

@@ -81,7 +81,7 @@
--frosted-border-light: rgba(255, 255, 255, 0.2); --frosted-border-light: rgba(255, 255, 255, 0.2);
--body-background-url: url(""); --body-background-url: url("");
--body-background-transition: background-image 0.8s ease-in-out; /* --body-background-transition: background-image 0.8s ease-in-out; */
} }
.dark { .dark {
@@ -145,7 +145,7 @@ body::before {
height: 100%; height: 100%;
z-index: -1; z-index: -1;
background: var(--body-background-url) center/cover no-repeat; background: var(--body-background-url) center/cover no-repeat;
transition: var(--body-background-transition); /* transition: var(--body-background-transition); */
} }
.striped-bg-red-translucent-diagonal { .striped-bg-red-translucent-diagonal {

View File

@@ -5,7 +5,7 @@ import "./index.css";
import "@radix-ui/themes/styles.css"; import "@radix-ui/themes/styles.css";
import { Theme } from "@radix-ui/themes"; import { Theme } from "@radix-ui/themes";
import { Header } from "@/components/sections/Header"; import { Header } from "@/components/sections/Header";
import DynamicPseudoBackground from "@/components/sections/Background"; import Background from "@/components/sections/Background";
import { useTheme } from "@/hooks/useTheme"; import { useTheme } from "@/hooks/useTheme";
import { NodeDataProvider } from "@/contexts/NodeDataContext"; import { NodeDataProvider } from "@/contexts/NodeDataContext";
import { LiveDataProvider } from "@/contexts/LiveDataContext"; import { LiveDataProvider } from "@/contexts/LiveDataContext";
@@ -46,10 +46,8 @@ const App = () => {
appearance="inherit" appearance="inherit"
scaling="110%" scaling="110%"
style={{ backgroundColor: "transparent" }}> style={{ backgroundColor: "transparent" }}>
{/* 使用动态背景组件 */} {/* 使用背景组件 */}
{publicSettings && ( {publicSettings && <Background publicSettings={publicSettings} />}
<DynamicPseudoBackground publicSettings={publicSettings} />
)}
<div className="min-h-screen flex flex-col text-sm"> <div className="min-h-screen flex flex-col text-sm">
<Header <Header
viewMode={viewMode} viewMode={viewMode}