class BgSwitcher { constructor(images, options = {}) { this.images = images; // 从localStorage中读取保存的索引 const savedIndex = localStorage.getItem('bgSwitcherIndex'); if (savedIndex !== null && !isNaN(savedIndex)) { this.index = parseInt(savedIndex); } else { this.index = 0; } this.container = options.container || document.body; this.interval = options.interval || 3000; this.effect = options.effect || BgSwitcher.fadeEffect; this.timer = null; this.apiTimer = null; this.apiUrl = null; this.apiInterval = 30000; this.startTime = 0; // 从localStorage中读取保存的剩余时间 const savedRemainingTime = localStorage.getItem('bgSwitcherRemainingTime'); this.remainingTime = savedRemainingTime !== null && !isNaN(savedRemainingTime) && savedRemainingTime >= 0 ? parseInt(savedRemainingTime) : this.interval; this.bgLayer = document.createElement('div'); this.isInitialLoad = true; // 从localStorage中读取API模式状态 const isApiMode = localStorage.getItem('bgSwitcherIsApiMode') === 'true'; if (isApiMode) { this.apiUrl = localStorage.getItem('bgSwitcherApiUrl') || null; const savedApiInterval = localStorage.getItem('bgSwitcherApiInterval'); this.apiInterval = savedApiInterval !== null && !isNaN(savedApiInterval) ? parseInt(savedApiInterval) : 30000; } // 监听页面可见性变化 this.handleVisibilityChange = this.handleVisibilityChange.bind(this); document.addEventListener('visibilitychange', this.handleVisibilityChange); // 监听页面卸载事件,确保保存状态 this.handleBeforeUnload = this.handleBeforeUnload.bind(this); window.addEventListener('beforeunload', this.handleBeforeUnload); this.bgLayer.style.position = 'fixed'; this.bgLayer.style.top = 0; this.bgLayer.style.left = 0; this.bgLayer.style.width = '100vw'; this.bgLayer.style.height = '100vh'; this.bgLayer.style.zIndex = '-1'; this.bgLayer.style.transition = 'opacity 1s'; this.bgLayer.style.opacity = 1; this.bgLayer.style.backgroundSize = 'cover'; this.bgLayer.style.backgroundColor = '#000000'; this.bgLayer.style.backgroundPosition = 'center'; this.bgLayer.style.filter = 'brightness(0.68)' this.container.style.backgroundColor = '#000000'; } setBg(url) { // 切换时先预加载目标图片,加载完成后再切换显示 const img = new Image(); img.onload = () => { if (this.isInitialLoad) { // 初始加载时,先设置背景图再添加到页面 this.bgLayer.style.backgroundImage = `url(${url})`; this.container.appendChild(this.bgLayer); this.isInitialLoad = false; } else { this.effect(this.bgLayer, url); } if(!this.isApiMode) { this.scheduleNext(); } }; img.onerror = () => { // 加载失败时处理 console.warn('背景图片加载失败:', url); if (this.isInitialLoad) { // 初始加载失败时,也添加背景层到页面 this.container.appendChild(this.bgLayer); this.isInitialLoad = false; } }; img.src = url; } next() { const nextIndex = (this.index + 1) % this.images.length; const nextUrl = this.images[nextIndex]; // 切换前先预加载 const img = new Image(); img.onload = () => { this.index = nextIndex; // 保存索引到localStorage localStorage.setItem('bgSwitcherIndex', this.index); this.effect(this.bgLayer, nextUrl); this.scheduleNext(); }; img.onerror = () => { // 加载失败时跳过 console.warn('背景图片加载失败:', nextUrl); this.scheduleNext(); }; img.src = nextUrl; } prev() { const prevIndex = (this.index - 1 + this.images.length) % this.images.length; const prevUrl = this.images[prevIndex]; // 切换前先预加载 const img = new Image(); img.onload = () => { this.index = prevIndex; // 保存索引到localStorage localStorage.setItem('bgSwitcherIndex', this.index); this.effect(this.bgLayer, prevUrl); this.scheduleNext(); }; img.onerror = () => { // 加载失败时跳过 console.warn('背景图片加载失败:', prevUrl); this.scheduleNext(); }; img.src = prevUrl; } start() { if (this.timer || this.apiTimer) return; // 如果处于API模式,启动API请求 if (this.apiUrl) { this.fetchRandomWallpaper(); } else { // 否则使用默认轮播 this.setBg(this.images[this.index]); } } /** * 安排下一次背景切换 */ scheduleNext() { if (this.timer) { clearTimeout(this.timer); } // 记录开始时间 this.startTime = Date.now(); // 使用剩余时间或默认间隔 const timeToWait = this.remainingTime > 0 ? this.remainingTime : this.interval; this.timer = setTimeout(() => { this.remainingTime = this.interval; // 重置剩余时间 // 保存剩余时间到localStorage localStorage.setItem('bgSwitcherRemainingTime', this.remainingTime); this.next(); }, timeToWait); } /** * 处理页面可见性变化 */ handleVisibilityChange() { if (document.hidden) { // 页面不可见时,暂停计时器并计算剩余时间 if (this.timer) { const elapsedTime = Date.now() - this.startTime; this.remainingTime = Math.max(0, this.remainingTime - elapsedTime); // 保存剩余时间到localStorage localStorage.setItem('bgSwitcherRemainingTime', this.remainingTime); clearTimeout(this.timer); this.timer = null; } // 暂停API计时器 if (this.apiTimer) { const elapsedTime = Date.now() - this.startTime; this.remainingTime = Math.max(0, this.remainingTime - elapsedTime); // 保存剩余时间到localStorage localStorage.setItem('bgSwitcherRemainingTime', this.remainingTime); clearTimeout(this.apiTimer); this.apiTimer = null; } } else { // 页面可见时,恢复计时器 if (!this.timer && !this.apiTimer && !this.apiUrl) { // 如果没有活跃的计时器,使用默认的轮播 this.scheduleNext(); } else if (this.apiTimer === null && this.apiUrl) { // 如果处于API模式但计时器未运行,恢复API请求 this.scheduleNextApiRequest(); } } } /** * 处理页面卸载事件,确保保存状态 */ handleBeforeUnload() { // 保存当前索引 localStorage.setItem('bgSwitcherIndex', this.index); // 保存API模式状态 localStorage.setItem('bgSwitcherIsApiMode', !!this.apiUrl); if (this.apiUrl) { localStorage.setItem('bgSwitcherApiUrl', this.apiUrl); localStorage.setItem('bgSwitcherApiInterval', this.apiInterval); } // 如果计时器在运行,计算并保存剩余时间 if (this.timer || this.apiTimer) { const elapsedTime = Date.now() - this.startTime; this.remainingTime = Math.max(0, this.remainingTime - elapsedTime); localStorage.setItem('bgSwitcherRemainingTime', this.remainingTime); } } stop() { if (this.timer) { clearTimeout(this.timer); this.timer = null; } // 重置剩余时间 this.remainingTime = this.interval; // 保存剩余时间到localStorage localStorage.setItem('bgSwitcherRemainingTime', this.remainingTime); } /** * 从API获取随机壁纸并定期更新 * @param {string} apiUrl - 获取随机壁纸的API地址 * @param {number} interval - 请求间隔时间(毫秒) */ startRandomApiSwitch(apiUrl, interval = 30000) { this.stop(); // 停止当前的轮播 this.apiInterval = interval; this.apiUrl = apiUrl; // 创建专用的API计时器 this.apiTimer = null; // 立即请求一次 this.fetchRandomWallpaper(); } /** * 从API获取随机壁纸 */ fetchRandomWallpaper() { // 记录开始时间,用于计算剩余时间 this.startTime = Date.now(); this.remainingTime = this.apiInterval; fetch(this.apiUrl) .then(response => { console.log(response); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { // 假设API返回的数据格式为 { wallpaperUrl: '图片地址' } const wallpaperUrl = data.wallpaperUrl || data.url || data.image; if (wallpaperUrl) { // 预加载图片 const img = new Image(); img.onload = () => { if (this.isInitialLoad) { // 初始加载时,先设置背景图再添加到页面 this.container.appendChild(this.bgLayer); this.isInitialLoad = false; } // 保存当前索引(使用-1标记这是API获取的图片) this.index = -1; localStorage.setItem('bgSwitcherIndex', -1); this.effect(this.bgLayer, wallpaperUrl); this.scheduleNextApiRequest(); }; img.onerror = () => { console.warn('API返回的壁纸加载失败:', wallpaperUrl); this.scheduleNextApiRequest(); }; img.src = wallpaperUrl; } else { console.warn('背景图片加载失败:', url); if (this.isInitialLoad) { console.warn('API返回的数据格式不正确,未找到壁纸地址'); // 初始加载失败时,也添加背景层到页面 this.container.appendChild(this.bgLayer); this.isInitialLoad = false; } this.scheduleNextApiRequest(); } }) .catch(error => { console.error('获取随机壁纸失败:', error); this.scheduleNextApiRequest(); }); } /** * 安排下一次API请求 */ scheduleNextApiRequest() { if (this.apiTimer) { clearTimeout(this.apiTimer); } // 使用剩余时间或默认间隔 const timeToWait = this.remainingTime > 0 ? this.remainingTime : this.apiInterval; this.apiTimer = setTimeout(() => { this.remainingTime = this.apiInterval; // 重置剩余时间 localStorage.setItem('bgSwitcherRemainingTime', this.remainingTime); this.fetchRandomWallpaper(); }, timeToWait); } /** * 停止API随机壁纸请求 */ stopRandomApiSwitch() { if (this.apiTimer) { clearTimeout(this.apiTimer); this.apiTimer = null; } this.apiUrl = null // 重置剩余时间 this.remainingTime = this.interval; localStorage.setItem('bgSwitcherRemainingTime', this.remainingTime); } static fadeEffect(layer, url) { layer.style.transition = 'opacity 1s'; layer.style.opacity = 0; setTimeout(() => { layer.style.backgroundImage = `url(${url})`; layer.style.opacity = 1; }, 500); } } // 使用示例 // 1. 默认本地图片轮播 // const images = [ // '/static/bg2.webp', // '/static/bg.jpg', // ]; // const bgSwitcher = new BgSwitcher(images, { interval: 5000 }); // 启动轮播 // bgSwitcher.start(); // 2. 随机API壁纸示例 // 创建一个新的BgSwitcher实例用于API模式 const apiBgSwitcher = new BgSwitcher([], { interval: 5000 }); // API模式不需要本地图片列表 // 模拟API函数,实际使用时替换为真实API地址 function createMockWallpaperApi() { // 模拟壁纸地址库 const mockWallpapers = [ '/static/bg2.webp', '/static/bg.jpg', ]; // 创建一个简单的服务器端点 if (window.mockWallpaperServer) { clearInterval(window.mockWallpaperServer); } // 模拟API响应 window.fetchRandomWallpaper = function () { return new Promise((resolve) => { setTimeout(() => { const randomIndex = Math.floor(Math.random() * mockWallpapers.length); resolve({ ok: true, json() { return { wallpaperUrl: mockWallpapers[randomIndex] } } }); }, 500); }); }; // 替换原生fetch以模拟API调用 window.originalFetch = window.fetch; window.fetch = function (url) { if (url === '/api/random-wallpaper') { return window.fetchRandomWallpaper(); } return window.originalFetch(url); }; console.log('模拟壁纸API已启动'); } // 初始化模拟API createMockWallpaperApi(); // 启动API模式的随机壁纸切换(每10秒请求一次) apiBgSwitcher.startRandomApiSwitch('/api/random-wallpaper', 10000); fetch("https://pic.xieyaxin.top/random.php") .then(response => { if(response.body instanceof ReadableStream) { return response.blob() } return response.json() }) .then(data => { console.log(URL.createObjectURL(data)); }) // 要停止API模式,使用 // apiBgSwitcher.stopRandomApiSwitch(); // 要切换回本地图片轮播,使用 // apiBgSwitcher.stopRandomApiSwitch(); // apiBgSwitcher.start(); // 启动默认轮播 // bgSwitcher.start();