如何让JS熔岩灯背景颜色随明暗主题切换?适配媒体查询
熔岩灯明暗模式颜色同步问题解决
我用JavaScript实现了熔岩灯效果作为页面背景,同时通过CSS媒体查询做了明暗模式切换按钮。现在主题切换能正常修改页面配色,但JS生成的熔岩灯颜色并未同步变化。想知道该用JavaScript还是CSS处理,目标是让熔岩灯颜色随暗色模式媒体查询同步切换。


原实现代码
// 配色模式控制 const btn = document.querySelector(".btn-toggle"); const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)"); const currentTheme = localStorage.getItem("theme"); if (currentTheme == "dark") { document.body.classList.toggle("dark-theme"); } else if (currentTheme == "light") { document.body.classList.toggle("light-theme"); } btn.addEventListener("click", function () { if (prefersDarkScheme.matches) { document.body.classList.toggle("light-theme"); var theme = document.body.classList.contains("light-theme") ? "light" : "dark"; } else { document.body.classList.toggle("dark-theme"); var theme = document.body.classList.contains("dark-theme") ? "dark" : "light"; } localStorage.setItem("theme", theme); }); // 创建PixiJS应用,设置背景色并自适应窗口大小 const app = new PIXI.Application({ background: "yellow", resizeTo: window }); // 将应用视图添加到DOM document.body.appendChild(app.view); // 基础设置 app.stage.eventMode = "dynamic"; app.stage.hitArea = app.screen; // 创建熔岩球容器 const container = new PIXI.Container(); app.stage.addChild(container); // 熔岩球配色数组 const colors = ["0x4361ee", "0x3a0ca3", "0x7209b7", "0xf72585"]; const blurFilter2 = new PIXI.BlurFilter(); // 生成随机熔岩球的辅助函数 function randomCircle() { const circle = new PIXI.Graphics(); const randomColor = Math.floor(Math.random() * colors.length); circle.beginFill(colors[randomColor]); circle.drawCircle(0, 0, (Math.random() * app.screen.width) / 4); circle.endFill(); const texture = app.renderer.generateTexture(circle); return { texture }; } // 熔岩球数组 const orbs = []; // 熔岩球参数 let trackSpeed = 0.03; let rotationSpeed = 0.01; // 设置熔岩球边界 const padding = app.screen.width / 4; const bounds = new PIXI.Rectangle( -padding, -padding, app.screen.width + padding * 2, app.screen.height + padding * 2 ); // 创建20个随机熔岩球 for (let i = 0; i < 20; i++) { const orb = PIXI.Sprite.from(randomCircle().texture); orb.anchor.set(0.5); container.addChild(orb); orb.direction = Math.random() * Math.PI * 2; orb.speed = 1; orb.turnSpeed = Math.random() - 0.8; orb.x = Math.random() * bounds.width; orb.y = Math.random() * bounds.height; orb.scale.set(1 + Math.random() * 0.3); orb.original = new PIXI.Point(); orb.original.copyFrom(orb.scale); orbs.push(orb); } // 给熔岩球添加模糊效果 container.filters = [blurFilter2]; blurFilter2.blur = 300; blurFilter2.quality = 35; // 鼠标位置存储 let mouseX; let mouseY; app.stage.on("pointermove", (event) => { mouseX = event.global.x; mouseY = event.global.y; }); // 动画计时器变量 let count = 0; // 监听动画更新 app.ticker.add((delta) => { count += 0.02; // 动画逻辑 for (let i = 0; i < orbs.length; i++) { const orb = orbs[i]; orb.direction += orb.turnSpeed * 0.01; orb.x += Math.sin(orb.direction) * orb.speed; orb.y += Math.cos(orb.direction) * orb.speed; orb.rotation = -orb.direction - Math.PI / 2; orb.scale.x = orb.original.x + Math.sin(count) * 0.2; // 边界循环处理 if (orb.x < bounds.x) { orb.x += bounds.width; } else if (orb.x > bounds.x + bounds.width) { orb.x -= bounds.width; } if (orb.y < bounds.y) { orb.y += bounds.height; } else if (orb.y > bounds.y + bounds.height) { orb.y -= bounds.height; } } });
解决方案:用JavaScript处理同步
因为熔岩灯是PixiJS生成的Canvas内容,CSS无法直接控制Canvas内部的图形颜色,所以必须通过JavaScript监听主题变化并同步更新熔岩灯的配色。具体步骤如下:
定义双配色方案
为明暗模式分别准备对应的熔岩球配色:// 浅色模式配色 const lightColors = ["0x4361ee", "0x3a0ca3", "0x7209b7", "0xf72585"]; // 深色模式配色 const darkColors = ["0x0d1b2a", "0x1b263b", "0x415a77", "0x778da9"]; // 根据当前主题初始化配色 let currentColors = (prefersDarkScheme.matches || currentTheme === "dark") ? darkColors : lightColors;更新熔岩球生成函数
修改randomCircle函数,使用当前主题对应的配色数组:function randomCircle() { const circle = new PIXI.Graphics(); const randomColor = Math.floor(Math.random() * currentColors.length); circle.beginFill(currentColors[randomColor]); circle.drawCircle(0, 0, (Math.random() * app.screen.width) / 4); circle.endFill(); const texture = app.renderer.generateTexture(circle); return { texture }; }添加熔岩球重绘函数
用于主题切换时重新生成所有熔岩球:function refreshLavaLampColors() { // 清空旧熔岩球 container.removeChildren(); orbs.length = 0; // 重新创建20个熔岩球 for (let i = 0; i < 20; i++) { const orb = PIXI.Sprite.from(randomCircle().texture); orb.anchor.set(0.5); container.addChild(orb); orb.direction = Math.random() * Math.PI * 2; orb.speed = 1; orb.turnSpeed = Math.random() - 0.8; orb.x = Math.random() * bounds.width; orb.y = Math.random() * bounds.height; orb.scale.set(1 + Math.random() * 0.3); orb.original = new PIXI.Point(); orb.original.copyFrom(orb.scale); orbs.push(orb); } // 同步背景色 app.renderer.backgroundColor = currentTheme === "dark" ? 0x121212 : 0xffffe0; }监听主题切换事件
包括按钮点击和系统主题变化:// 修改按钮点击事件,添加配色更新逻辑 btn.addEventListener("click", function () { let theme; if (prefersDarkScheme.matches) { document.body.classList.toggle("light-theme"); theme = document.body.classList.contains("light-theme") ? "light" : "dark"; } else { document.body.classList.toggle("dark-theme"); theme = document.body.classList.contains("dark-theme") ? "dark" : "light"; } // 更新当前配色 currentColors = theme === "dark" ? darkColors : lightColors; // 重绘熔岩灯 refreshLavaLampColors(); localStorage.setItem("theme", theme); }); // 监听系统主题变化 prefersDarkScheme.addEventListener("change", (e) => { const newTheme = e.matches ? "dark" : "light"; currentColors = newTheme === "dark" ? darkColors : lightColors; // 同步body类名和本地存储 document.body.classList.remove("light-theme", "dark-theme"); document.body.classList.add(`${newTheme}-theme`); localStorage.setItem("theme", newTheme); // 重绘熔岩灯 refreshLavaLampColors(); });初始化时匹配主题
在初始创建熔岩球前,确保currentColors已根据当前主题正确设置,保证初始状态的熔岩灯颜色和主题匹配。
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

