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模式 let 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) window.addEventListener("pageshow", function (event) { if (event.persisted) { apiBgSwitcher = new BgSwitcher([], { interval: 5000 }) 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();