shared worker 可实现跨窗口主题实时同步:状态托管于 worker,通过 postmessage 广播变更,页面监听并更新 css 变量或 class;不支持时自动降级为 localstorage + storage 事件。

Shared Worker 可以让多个浏览器上下文(如不同标签页、iframe)共享同一个 Worker 实例,天然适合做跨窗口的状态同步。要实现“无刷新的跨窗口主题皮肤实时同步”,核心思路是:把主题配置作为中心状态托管在 Shared Worker 中,所有页面通过 port 与之通信,监听变更并动态更新 CSS 变量或 class。
主题状态统一托管在 Shared Worker 中
Shared Worker 是独立于页面生命周期运行的,即使某个页面关闭,只要还有其他页面连接着,Worker 就持续存活。因此它非常适合做轻量级的“状态服务”。你可以在其中维护一个主题对象(如 { mode: 'dark', primaryColor: '#4a6fa5' }),并通过 postMessage 广播变更。
- Worker 初始化时可从 localStorage 读取上次保存的主题,作为初始值
- 提供
setTheme(theme)方法,更新状态并port.postMessage({ type: 'theme:update', data: theme })广播给所有活跃端口 - 每个连接的页面需调用
port.start()并监听message事件响应更新
页面端建立连接并响应主题变更
每个页面加载时,创建 new SharedWorker('./theme-worker.js'),拿到 worker.port 后立即启动通信通道。之后只需监听消息,提取主题数据并应用到 DOM 即可。
- 推荐用 CSS 自定义属性(
:root)管理皮肤变量,例如document.documentElement.style.setProperty('--primary-color', theme.primaryColor) - 也可切换
document.body.className控制暗色/亮色模式类名,配合预设 CSS 规则 - 首次连接时主动发送
{ type: 'theme:request' }请求当前主题,避免白屏或错配
支持手动切换 + 外部触发(如系统偏好变更)
用户点击切换按钮时,页面向 Shared Worker 发送变更指令;同时建议监听 prefers-color-scheme 媒体查询变化,自动同步系统级深浅偏好。
- 监听
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ...),触发port.postMessage({ type: 'theme:auto', mode: 'dark' }) - Worker 收到后合并逻辑(例如“用户手动设为 light”优先级高于系统偏好),再广播最终结果
- 所有页面收到广播后统一更新,无需刷新、不依赖服务端、零延迟
注意兼容性与降级策略
Shared Worker 在 Safari 中长期不支持(截至 Safari 17.4 仍不可用),且部分隐私模式下会被禁用。必须做好回退方案。
- 检测
typeof SharedWorker !== 'undefined',不支持时改用localStorage + storage事件模拟同步 - storage 事件虽有毫秒级延迟且无法传递复杂对象,但对主题切换这类低频操作足够可靠
- 可封装统一的
ThemeSync类,内部自动选择 Shared Worker 或 localStorage 策略,业务代码无感知










