【免费下载链接】DarkumentA sleek, privacy-focused browser extension that brings a native dark mode experience to online documents. Built with clean UI/UX principles for Chromium and Opera browsers to reduce eye strain and improve readability.项目地址https://gitcode.com/gh_mirrors/da/Darkument点击查看免费下载Darkument 是一款面向 Chromium 与 Opera 浏览器的深色模式扩展Manifest V3 架构用一次点击即可反转 PDF、文档和网页页面打造护眼的暗色阅读体验。它最受用户欢迎的特性是独立记住每个标签页的开关状态——多个 PDF 来回切换互不串扰。今天我们就深入源码拆解一个只活在内存里的 Map 是如何完成这套状态管理的。Darkument 深色模式扩展将 PDF 页面反转为黑底白字的深色效果截图为什么每个标签页都需要独立状态想象一个真实场景你同时打开了 3 个标签页——一份 SQL 用例 PDF、一篇参考文献、一个在线文档。你只想把第一份 PDF 反转为深色其余保持原样。如果扩展内部只用一个全局布尔值记录深色模式开没开切换标签页时就会出问题切回第二个标签页图标状态显示的是别人的状态再点一次图标无法判断当前页面到底该开启还是关闭所以 Darkument 的状态管理从第一行代码就确立了原则以标签页为粒度记录状态源码位于 src/background.js。volatile Map只活在内存里的状态仓库整个状态管理的基础是 Service Worker 中的一行声明background.js 第 3 行// src/background.js const tabStates new Map();这个Map的结构非常简单键key值value含义tab.id浏览器分配的整数 IDtrue/false该标签页深色模式是否开启这里有两个值得新手注意的设计点为什么用Map而不是普通对象标签页 ID 是动态增减的整数Map对任意类型的键都保持 O(1) 的查找、写入与删除性能且delete语义清晰天然适合随开随关的数据。为什么叫volatile易失它只存在于 Service Worker 的内存中——没有写入chrome.storage没有写入 localStorage浏览器一关状态归零。这不是缺陷而是刻意为之的设计决策下文解释。在 src/manifest.json 中可以看到background.js以 MV3 的service_worker方式注册也就是说这个 Map 的生命周期与浏览器会话绑定而不是与某个页面绑定。状态生命周期创建 → 读取 → 恢复 → 清理一个完整的设计不只是存进去还要保证状态在每个关键节点都正确。Darkument 用三个事件覆盖了标签页的一生。1. 创建与读取一次点击完成翻转点击扩展图标时Service Worker 先读旧状态再写新状态background.js 第 9 行、第 67-68 行const isActive tabStates.get(tab.id) || false; // 读无记录默认视为关 // ...向该标签页注入深色覆盖层脚本后... tabStates.set(tab.id, !isActive); // 写翻转状态注意|| false这个兜底第一次点击时 Map 里没有该标签页的记录get返回undefined兜底后按关闭处理逻辑永远确定。随后扩展会通过chrome.scripting.executeScript把反转覆盖层注入目标标签页并同步更新图标与角标。Darkument 深色模式扩展开启前的 PDF 页面正常模式效果浏览器右上角显示扩展图标2. 恢复页面刷新后状态角标不丢失这是最容易被忽略的细节。当用户刷新页面或同标签页跳转 URL 时页面 DOM 会重建——但tabStates里的记录还在。扩展通过监听chrome.tabs.onUpdated来补救 UI 一致性background.js 第 123-154 行chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) { if (changeInfo.status complete tabStates.has(tabId)) { // 页面加载完成且 Map 中仍记录该标签页为开启 → 重新设置图标和 ON 角标 } });判断条件是页面加载完成Map 中仍有记录二者缺一不可确保图标和角标始终与真实状态同步。3. 清理标签页关闭即删除防止内存泄漏最后一段生命周期代码只有三行background.js 第 118-120 行chrome.tabs.onRemoved.addListener((tabId) { tabStates.delete(tabId); });如果没有这个监听器Map 会不断积累已关闭标签页的死键。这三行补上后状态的生命周期与标签页完全对齐随标签页生随标签页灭。Darkument 深色模式扩展恢复为正常模式后的 PDF 页面右上角扩展图标处于 ON 状态为什么不用 chrome.storage 持久化状态这是理解volatile设计的关键。很多人会想把状态存下来下次打开浏览器还能恢复不是更好吗问题出在tab.id只在当前浏览器会话内有效。重启浏览器后即便打开同一个网址浏览器也会分配一个全新的 tab ID。如果状态被持久化重启后残留的旧tab.id → true记录可能恰好命中新标签页复用的旧 ID结果是一个从未被操作过的标签页图标莫名显示ON状态而深色模式本质上是会话级的体验偏好——你不太可能要求浏览器记住我上次把哪个页面翻黑了。volatile Map 恰好满足生命周期与浏览器会话严格一致零存储开销、零磁盘写入与 Darkument本地运行、零隐私足迹的设计理念见 PRIVACY.md完全吻合。视觉反馈图标与角标的逐标签页同步状态存对了还要看得见。每次状态翻转后扩展会调用两个按tabId隔离的 APIbackground.js 第 71-97 行chrome.action.setIcon({ tabId, path })开启时切换为点亮图标icons/icon1_*.png关闭时切换为默认图标icons/icon2_*.png只影响当前标签页chrome.action.setBadgeText({ tabId, text: ON })开启时打上绿色 ON 角标背景色#4CAF50关闭时清空这样哪怕同时开着 5 个标签页扫一眼图标就能分辨哪几个处于深色模式。设计演进从早期版本就已定型翻看仓库中的早期存档版本 oldVersionFiles/backgroundOld.js 和 oldVersionFiles/background102correctOrder.js可以看到tabStatesMap 与三事件生命周期从第一版就已存在后续版本主要优化的是图标资源和交互细节。这说明volatile Map 标签页生命周期事件是经过验证的稳定架构而非后期补丁。总结回顾 Darkument 的标签页状态管理核心其实只有四件事️一个 Maptab.id → booleanO(1) 读写内存级存储➕写入点击图标时翻转状态set读取带|| false兜底恢复监听onUpdated页面加载完成后重建图标与角标清理监听onRemoved标签页关闭即delete杜绝泄漏对想学习浏览器扩展状态管理的开发者来说这套不到 30 行核心逻辑的设计展示了如何用最简单的数据结构做出无泄漏、无串扰、零持久化成本的会话级状态管理。延伸阅读架构说明ARCHITECTURE.md项目介绍README.md权限引导页源码src/pages/thankyou.html测试说明docs/NoteForTesters.txt赞分享【免费下载链接】DarkumentA sleek, privacy-focused browser extension that brings a native dark mode experience to online documents. Built with clean UI/UX principles for Chromium and Opera browsers to reduce eye strain and improve readability.项目地址https://gitcode.com/gh_mirrors/da/Darkument点击查看免费下载相关推荐QQ空间历史说说导出教程三步跑通把多年旧动态完整存成 Excel 和图片QQ空间历史说说导出教程三步跑通把多年旧动态完整存成 Excel 和图片 翻到五年前的空间页面想截图保存几页旧说说结果页面转圈半天加载不出来图也裂了一网页爬虫数据分析HsMod炉石传说的终极增强插件3分钟开启你的个性化游戏体验HsMod炉石传说的终极增强插件3分钟开启你的个性化游戏体验 炉石传说HsMod是一款基于BepInEx框架开发的开源游戏增强插件通过代码修补技术为玩家带游戏开发Requests 库 Cookie Jar 深度解析RequestsCookieJar 如何让 Session 记住登录状态Requests 库 Cookie Jar 深度解析RequestsCookieJar 如何让 Session 记住登录状态 本篇技术指南以 RequestsAI 应用大模型AI Agent代码智能体上一篇pi-subagents 工具选择策略优化代理能力配置的最佳实践下一篇Nuxt项目CLI配置完全指南个性化你的开发体验创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考