Obsidian Quick Note
一个专注于「快速记录」的 Chrome 扩展。看到网页上有值得记的内容时,点一下工具栏图标,就能把片段保存为 Markdown 笔记到 Obsidian。
为什么做这个项目
我一直在用 Obsidian 管理笔记,但官方 Obsidian Web Clipper 更像是一个完整的网页剪藏工具:它会自动提取全文、高亮、模板渲染,适合做资料归档。而我的实际场景更多是:
- 看文章时突然想到一个观点,想快速记下来
- 看到一段有用的代码或引用,想保存到自己的笔记里
- 逛论坛或社交媒体时,想把某个讨论片段顺手扔进仓库
这些场景不需要完整的网页剪藏,而是需要一种快速方便的记录方式。所以决定做一个更轻量的扩展,核心目标就是:打开快、输入少、保存稳。
产品定位
Obsidian Quick Note 不是 Obsidian Web Clipper 的替代品,而是补充。
- Web Clipper:完整保存网页内容,适合资料收集
- Quick Note:快速记录想法片段,适合随手记
两者可以共存。用户可以用 Web Clipper 归档整篇文章,同时用 Quick Note 记录自己的思考和摘录。
核心功能
1. 一键保存到 Obsidian
扩展通过 obsidian://new URI 协议把 Markdown 笔记交给 Obsidian 处理。用户只需要填写仓库名和默认保存文件夹,不需要安装任何 Obsidian 插件或配置外部服务。
2. 自动提取元数据
保存时会自动从网页提取以下信息,生成 YAML Frontmatter:
title:页面标题(自动去除站点名后缀)url:来源链接author:作者(支持 meta、JSON-LD、DOM 选择器多层提取)description:页面描述site:站点名date:保存时间tags:默认标签
3. 选中文本自动带入
在网页上框选文字后打开 popup,选中的内容会自动进入编辑器。如果在同一标签页多次框选,新内容会追加到已有草稿后面,而不是覆盖,方便把多个片段组织成一条笔记。
4. 标签页级草稿隔离
每个标签页拥有独立的草稿。切换到其他标签页不会互相覆盖,刷新或关闭标签页后草稿会自动清理,避免把旧页面的内容误保存到新页面。
5. 右键菜单快捷入口
在网页任意位置、选中文本或链接上右键,都能看到 "Obsidian Quick Note" 菜单项,点击即可打开 popup。
6. 兜底下载
如果 Obsidian URI 调用失败(比如仓库名错误、Obsidian 未安装),扩展会自动把 Markdown 文件下载到本地,避免内容丢失。
7. 中英文自动切换
根据 Chrome 的界面语言自动切换中文或英文 UI。
插件使用截图
插件页面图:

插件保存位置和 Frontmatter 可以临时切换:

插件设置页面:


使用演示:
可以按快捷键呼出,快捷键可以自定义。或者在右上角把插件 pin 住,点击即可呼出。再或者鼠标右键也可以有插件的快捷操作。

开发过程中遇到的几个关键问题
问题 1:如何让 Obsidian 保存更稳定
最早考虑过用 Obsidian Local REST API 插件,通过 HTTP 直接写入文件。但测试后发现:如果 Obsidian 没有运行,请求会失败;扩展尝试唤醒 Obsidian 时,Chrome 的协议确认框又会打断 popup 的异步流程。
最终采用了和官方 Web Clipper 相同的方案:obsidian://new + 剪贴板。这个方案的优势是零配置、能唤醒 Obsidian、大内容通过剪贴板传输不受 URL 长度限制。
问题 2:选中文本在第二次打开 popup 时丢失
最初的实现是 editor.value = draft.content || selectedText || ''。第一次框选后,关闭 popup 时会把选中文本保存到 draft.content。第二次框选时,draft.content 已经不为空,新的 selectedText 被忽略。
解决方式是引入 mergeSelectedText():新选中文本追加到草稿后面,如果已经存在则去重。这样既保留了用户手动输入的内容,又能逐步累积摘录。
问题 3:草稿在不同标签页互相覆盖
早期所有标签页共用同一个 oqn:draft key。在标签页 A 写了一半,切换到标签页 B 打开 popup,看到的是 A 的内容,很容易误保存。
解决方式是把 storage 结构改为 oqn:drafts = { [tabId]: Draft },每个标签页独立读写,并在标签页关闭或刷新时自动清理。
技术栈
- Chrome Extension Manifest V3
- TypeScript
- Vite(构建)
- Vitest(测试,131 个测试全部通过)
- 自定义元数据提取逻辑(参考 Defuddle 思路,独立实现)
后续计划
- 上架后根据用户反馈持续优化
- 考虑补充英文商店翻译和 GitHub release tag
相关链接
- GitHub: https://github.com/kains2866/obsidian-quick-note
- 隐私政策: https://kains2866.github.io/obsidian-quick-note/privacy.html
v0.3.2:保留框选内容中的图片
0.3.2 是一个聚焦「选中文本」体验的版本。之前的实现只把纯文本带入编辑器,但用户框选网页内容时往往会同时选中图片,这些图片直接丢失会比较可惜。
这个版本主要做了什么
- 框选网页内容时,如果选区中包含图片,图片链接会按原始位置以 Markdown 图片语法自动带入正文。
- 设置页增加「保留框选内容中的图片链接」开关,默认开启。
- 支持常见懒加载图片(
data-src/data-lazy-src/data-original)。 - 自动过滤小于 20×20 像素的图片以及临时 blob URL 图片,避免把图标、占位图也存进笔记。
- 自动将相对路径图片 URL 补全为绝对 URL。
- 保留
<br>换行,同时减少多层<div>嵌套时产生的多余空行。
开发过程中的取舍
图片提取的边界
网页图片的实现方式差异很大:普通 <img> 最简单;懒加载图片通常把真实地址放在 data-src 这类属性里;而 Shadow DOM、Canvas 或某些评论区的图片则完全拿不到。我覆盖了前两种常见情况,并在说明里坦诚地告诉用户:特殊渲染方式的图片建议手动截图,避免给用户不切实际的期待。
HTML 到 Markdown 的转换干净程度
直接把选区的 HTML 转成 Markdown 很容易产生大量空行,尤其是现代网页喜欢用层层 <div> 包裹。0.3.2 做了一些比较保守的清理:保留 <br> 这种明确的换行,同时合并相邻的空行。这个度很难一次性调完美,后续版本还在继续根据实际网页优化。
v0.4.0:网站自动 tags 与设置页重构
0.4.0 是从 0.3.x 跨入 0.4.x 的一次较大迭代。这个版本主要想解决两个问题:一是 popup 标签栏在 tag 多的时候布局会崩;二是不同网站需要自动带上不同的默认标签。
这个版本主要做了什么
网站自动 tags
- 支持按域名规则为匹配网站自动预选 tags。比如访问
bilibili.com时自动勾选bilibili,访问网易新闻时自动勾选wangyi。 - 域名规则支持根域名、路径前缀和完整 URL 自动提取。输入
163.com/news能匹配网易新闻的子路径。 - Options 页支持对规则进行编辑、删除和简单校验,避免输入明显错误的域名。
Popup 标签栏重构
- 标签栏改为单行横向滚动,滚动条隐藏,鼠标滚轮可以左右滑动。
- tag 胶囊固定高度,长 tag 显示省略号,不再撑大 popup 高度。
- 全局标签与临时标签的视觉区分更明显,减少误删。
设置页与保存流程优化
- 设置页关闭前如果还有未保存的改动,会弹出浏览器确认提示。
- 「保存到」编辑面板改为自动保存,再次点击保存路径行即可收起。
- URL / 标题的 Frontmatter 勾选移入「保存到」编辑面板,主界面更简洁。
- 扩展名称、作者信息、GitHub 链接、默认标签等元数据统一维护,避免多处硬编码。
修复
- 修复同一视频连续呼出 popup 时重复插入相同进度链接的问题。
开发过程中的一些取舍
域名规则的匹配粒度
一开始只做了简单的字符串包含匹配,结果出现 bilibili.com 的规则也可能匹配到 bilibili.com.wikia.com 这种无关站点。后来改用 URL 解析后的 hostname 做匹配,并允许带 path 前缀,才既保证精确又保留灵活性。
横向滚动的实现
tag 栏如果换行,popup 高度会变得不可控;如果截断隐藏,用户又看不到后面的 tag。最后选择了横向滚动 + 隐藏滚动条的方案,在保持 popup 紧凑的同时,让鼠标滚轮可以直接左右滑动。
v0.4.1:修复右键选中文本丢失
0.4.1 是一个小版本,只针对一个用户反馈最集中的 bug 做修复。
这个版本主要做了什么
- 修复通过右键菜单打开 popup 时,选中的文本无法导入编辑器的问题(GitHub issue #1)。
- content script 现在会缓存最近一次的非空选区,并在浏览器清除选区后自动回退到缓存内容。
- 左键点击页面清除选区会同步清空缓存;右键唤出菜单则保留缓存,确保 popup 打开时文本还在。
开发过程中的发现
这个问题的根因是浏览器事件顺序:右键打开 context menu 时,selectionchange 事件可能会在 popup 读取选区之前或之后触发,不同操作系统下表现不一致。直接依赖当前选区读取很容易拿到空字符串。
我的解决办法是在 content script 里维护一个「最后有效选区」的缓存:只要用户框选过非空文本,就把它存起来;当 popup 读取时,优先取当前选区,如果当前选区为空再取缓存。同时用鼠标按键类型判断用户意图——左键点击页面意味着用户想放弃当前选区,这时清空缓存;右键则是想保存,这时保留缓存。
这样就把「浏览器选区是否还在」和「用户是否想保存这段文本」两个问题解耦了。
v0.4.2:稳定版迭代与主题切换
经过 0.4.x 几个小版本的连续打磨,Obsidian Quick Note 在 v0.4.2 进入了一个相对稳定的状态。这个版本没有激进的重构,而是把之前已经验证的功能做扎实,同时补上了用户反馈最多的一块:主题切换。
这个版本主要做了什么
主题与视觉
- 设置页增加了主题切换按钮,可以在「浅色 / 深色 / 自动」三种模式之间循环切换。
- popup 弹窗与设置页共用同一套主题变量,切换后即时生效,不需要刷新扩展或重启浏览器。
- 标签栏在 tag 数量较多时支持横向滚动,滚动条全程隐藏,保持界面干净。
- 临时添加的 tag 与固定 tag 做了视觉区分,减少误操作。
设置页体验优化
- 设置页内容越来越多后,用户容易忘记保存。现在如果修改了设置后尝试关闭标签页,会弹出确认提示,避免配置丢失。
- 域名规则支持更智能的匹配:输入
163.com/news这类带 path 的规则也能正确识别;粘贴完整 URL 时会自动保留 path。 - 已添加的域名规则支持编辑,编辑状态下右侧按钮变为保存/删除,减少误删。
- 默认 tag 池支持「自动选中第一个 tag」的开关,适配不同用户的使用习惯。
稳定性修复
- 修复了设置页快捷键一直显示「读取中」的问题。
- 修复了通过右键菜单打开 popup 时,选中文本偶尔丢失的问题(#1)。
- 修复了域名规则可能误匹配到无关站点的问题。
- 修复了在 SPA 页面跳转后,已缓存的选中文本可能带入新页面的问题。
开发过程中的一些取舍
右键选中文本的处理逻辑
有用户反馈右键打开 popup 时选中的文本没有自动填入。这个问题比表面复杂:浏览器在不同操作系统、不同触发方式下,selectionchange 和 contextmenu 的事件顺序并不完全一致。如果 popup 打开时机早于选中文本稳定时机,就会读到空字符串。
我最后采用了一个保守策略:只在页面上确实存在选区(window.getSelection() 返回非空 range)时才把选中文本带入 popup;如果用户已经点过页面其他地方、选区被清空,就不再保留旧的缓存。这样既能覆盖大部分正常框选场景,也避免了把用户不想保存的内容硬塞进去。
Safari 适配的尝试与放弃
在 0.4.2 之前,我也尝试过把扩展通过 safari-web-extension-converter 转换成 Safari 版本。转换和编译本身可以成功,但实际测试中发现:Safari 对 obsidian:// URI 的处理、剪贴板写入以及部分 storage API 的行为和 Chrome 有差异,导致保存反应慢甚至失败。考虑到维护成本和当前阶段的主要用户群,我暂时放弃了 Safari 版本,把精力集中在把 Chrome 版本做稳。
主题系统的实现方式
一开始我考虑直接用 prefers-color-scheme 做自动主题,但扩展的 popup 和 options 是两个独立的 HTML 页面,如果不统一存储主题状态,用户手动切换后两个页面会表现不一致。最终我把主题选择存在 chrome.storage.sync 里,两个页面启动时都读取同一份状态,并监听变化做同步。
当前状态
v0.4.2 已经 push 到 GitHub 主分支,并打包为 obsidian-quick-note-v0.4.2.zip。商店版本也同步更新到了 0.4.2。
这个版本之后,我会先观察一段时间用户反馈,重点看右键盘选、域名规则匹配、深色模式这几块是否还有边缘情况,再决定下一步是继续修 bug 还是进入 0.5.0 的功能迭代。