feat: 新增本地背景功能与民谣歌单,重构背景切换逻辑
1. 新增两个后台接口获取本地背景文件列表和随机背景 2. 重构页面背景切换系统,增加本地默认背景模式并支持本地存储配置 3. 调整背景切换按钮样式为纯图标风格,新增本地模式开关 4. 新增民谣精选歌单文件 5. 优化主题轮播逻辑,支持本地背景自动轮换
This commit is contained in:
+124
-13
@@ -4,6 +4,15 @@ class ToolboxHome {
|
||||
constructor() {
|
||||
this.currentTheme = 0;
|
||||
this.openInModal = true;
|
||||
this.localBgMode = false;
|
||||
this.localBgFiles = [];
|
||||
this.localBgIndex = 0;
|
||||
this.localRotationInterval = null;
|
||||
// 从 localStorage 恢复状态
|
||||
try {
|
||||
this.localBgMode = localStorage.getItem('tb_home_local_bg') === '1';
|
||||
this.openInModal = localStorage.getItem('tb_home_open_mode') !== '0';
|
||||
} catch {}
|
||||
this.themes = [
|
||||
{
|
||||
name: '夜空星轨',
|
||||
@@ -263,11 +272,6 @@ class ToolboxHome {
|
||||
tabPages.appendChild(lowToolsPage);
|
||||
tabPages.appendChild(bookmarksPage);
|
||||
|
||||
// 创建换背景按钮
|
||||
const changeBgBtn = document.createElement('button');
|
||||
changeBgBtn.className = 'change-background-btn';
|
||||
changeBgBtn.innerHTML = '🎨 换背景';
|
||||
|
||||
// 组装页面
|
||||
mainContainer.appendChild(header);
|
||||
mainContainer.appendChild(tabBar);
|
||||
@@ -277,7 +281,6 @@ class ToolboxHome {
|
||||
document.body.appendChild(backgroundContainer);
|
||||
document.body.appendChild(effectsContainer);
|
||||
document.body.appendChild(mainContainer);
|
||||
document.body.appendChild(changeBgBtn);
|
||||
// 顶部右侧滑块(弹窗/本地切换)
|
||||
const controls = document.createElement('div');
|
||||
controls.className = 'top-right-controls';
|
||||
@@ -288,7 +291,24 @@ class ToolboxHome {
|
||||
</label>
|
||||
`;
|
||||
document.body.appendChild(controls);
|
||||
this.ensureBgLoaded(0, true);
|
||||
// 换背景按钮容器(图标按钮 + 本地模式开关,水平排列,放底部)
|
||||
const bgBtnWrapper = document.createElement('div');
|
||||
bgBtnWrapper.className = 'bg-btn-wrapper';
|
||||
bgBtnWrapper.innerHTML = `
|
||||
<button class="change-background-btn" title="切换背景(或按 B 键)" aria-label="change-background"></button>
|
||||
<label class="ios-switch bg-local-switch" title="本地默认背景模式">
|
||||
<input type="checkbox" id="local-bg-switch" aria-label="local-bg-toggle">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
`;
|
||||
document.body.appendChild(bgBtnWrapper);
|
||||
// 根据 localStorage 状态初始化背景模式
|
||||
if (this.localBgMode) {
|
||||
this.startLocalBgRotation();
|
||||
} else {
|
||||
this.ensureBgLoaded(0, true);
|
||||
this.startThemeRotation();
|
||||
}
|
||||
|
||||
const iconPicker = document.createElement('div');
|
||||
iconPicker.className = 'icon-picker';
|
||||
@@ -624,7 +644,7 @@ class ToolboxHome {
|
||||
setupEventListeners() {
|
||||
// 换背景按钮事件
|
||||
document.querySelector('.change-background-btn').addEventListener('click', () => {
|
||||
this.ensureBgLoaded(this.currentTheme, false);
|
||||
this.nextTheme();
|
||||
});
|
||||
|
||||
// 工具卡片点击效果 + 打开方式(委托方式,支持动态加载)
|
||||
@@ -648,10 +668,28 @@ class ToolboxHome {
|
||||
});
|
||||
|
||||
// 滑块切换事件
|
||||
const switchEl = document.getElementById('open-mode-switch');
|
||||
if (switchEl) {
|
||||
switchEl.addEventListener('change', () => {
|
||||
this.openInModal = !!switchEl.checked;
|
||||
const localBgSwitch = document.getElementById('local-bg-switch');
|
||||
const openModeSwitch = document.getElementById('open-mode-switch');
|
||||
if (localBgSwitch) {
|
||||
localBgSwitch.checked = this.localBgMode;
|
||||
localBgSwitch.addEventListener('change', () => {
|
||||
this.localBgMode = !!localBgSwitch.checked;
|
||||
try { localStorage.setItem('tb_home_local_bg', this.localBgMode ? '1' : '0'); } catch {}
|
||||
if (this.localBgMode) {
|
||||
this.stopThemeRotation();
|
||||
this.startLocalBgRotation();
|
||||
} else {
|
||||
this.stopLocalBgRotation();
|
||||
this.ensureBgLoaded(this.currentTheme, true);
|
||||
this.startThemeRotation();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (openModeSwitch) {
|
||||
openModeSwitch.checked = this.openInModal;
|
||||
openModeSwitch.addEventListener('change', () => {
|
||||
this.openInModal = !!openModeSwitch.checked;
|
||||
try { localStorage.setItem('tb_home_open_mode', this.openInModal ? '1' : '0'); } catch {}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1264,6 +1302,10 @@ class ToolboxHome {
|
||||
}
|
||||
|
||||
nextTheme() {
|
||||
if (this.localBgMode) {
|
||||
this.nextLocalBg();
|
||||
return;
|
||||
}
|
||||
this.currentTheme = (this.currentTheme + 1) % this.themes.length;
|
||||
this.applyTheme(this.currentTheme);
|
||||
|
||||
@@ -1417,12 +1459,81 @@ class ToolboxHome {
|
||||
}
|
||||
|
||||
startBackgroundRotation() {
|
||||
// 每30秒自动切换背景
|
||||
this.startThemeRotation();
|
||||
}
|
||||
|
||||
startThemeRotation() {
|
||||
if (this.localBgMode) return;
|
||||
this.stopThemeRotation();
|
||||
this.rotationInterval = setInterval(() => {
|
||||
this.nextTheme();
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
stopThemeRotation() {
|
||||
if (this.rotationInterval) {
|
||||
clearInterval(this.rotationInterval);
|
||||
this.rotationInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
startLocalBgRotation() {
|
||||
this.loadLocalBgFiles().then(() => {
|
||||
this.stopLocalBgRotation();
|
||||
this.localRotationInterval = setInterval(() => {
|
||||
this.nextLocalBg();
|
||||
}, 30000);
|
||||
});
|
||||
}
|
||||
|
||||
stopLocalBgRotation() {
|
||||
if (this.localRotationInterval) {
|
||||
clearInterval(this.localRotationInterval);
|
||||
this.localRotationInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
async loadLocalBgFiles() {
|
||||
if (this.localBgFiles.length > 0) return this.localBgFiles;
|
||||
try {
|
||||
const r = await fetch('/api/home/bg/default-list?t=' + Date.now());
|
||||
const j = await r.json();
|
||||
if (j.ok && j.files.length) {
|
||||
this.localBgFiles = j.files;
|
||||
this.localBgIndex = 0;
|
||||
// 加载第一张
|
||||
const imgs = document.querySelectorAll('.background-image');
|
||||
if (imgs.length) {
|
||||
imgs.forEach(img => { img.src = `/home-bg/default-c21f969b/${this.localBgFiles[0]}?v=${Date.now()}`; });
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
return this.localBgFiles;
|
||||
}
|
||||
|
||||
async nextLocalBg() {
|
||||
if (!this.localBgFiles.length) {
|
||||
await this.loadLocalBgFiles();
|
||||
if (!this.localBgFiles.length) return;
|
||||
}
|
||||
// 随机选取,避免重复当前
|
||||
let newIndex;
|
||||
if (this.localBgFiles.length > 1) {
|
||||
do {
|
||||
newIndex = Math.floor(Math.random() * this.localBgFiles.length);
|
||||
} while (newIndex === this.localBgIndex);
|
||||
} else {
|
||||
newIndex = 0;
|
||||
}
|
||||
this.localBgIndex = newIndex;
|
||||
const file = this.localBgFiles[this.localBgIndex];
|
||||
const imgs = document.querySelectorAll('.background-image');
|
||||
if (imgs.length) {
|
||||
imgs.forEach(img => { img.src = `/home-bg/default-c21f969b/${file}?v=${Date.now()}`; });
|
||||
}
|
||||
this.showNotification(`本地背景: ${this.localBgIndex + 1}/${this.localBgFiles.length}`);
|
||||
}
|
||||
|
||||
showNotification(message) {
|
||||
// 创建通知元素
|
||||
const notification = document.createElement('div');
|
||||
|
||||
Reference in New Issue
Block a user