复制操作去哪里?
页面可以调用名为 clipboard.write 的方法。它在预加载脚本中的实现是一个包装函数。关键问题是:它发送了什么,又由哪段代码接收?
使用REA跟踪Notion如何将文本和HTML复制到系统剪贴板。 在每个步骤显示代码。
一个示例提示与Notion的本地应用程序包可供你的编程助手.
REA查找从哪里开始阅读
用 REA 分析标签页的预加载脚本,可以找到暴露给页面的 API,以及发送 IPC 请求的调用。两个结果都给出了在压缩代码中的位置:
REA 分析结果 → 两个源码位置
api_key: "__electronApi"
api_status: "dynamic"
source: preload.js:1:22764–22828
operation: "invoke"
channel_expression: "e"
source: preload.js:1:6486–6522
analyze_javascript_application 分析结果中的部分字段,来自 Notion 标签页的预加载脚本,使用 REA 4.1.0 记录。位置对应原始压缩包中的行号和从零开始的列号。
助手打开这些位置,在组装的 API 中找到剪贴板成员,再读取 invokerInMain。调用处传入 notion:clipboard:write,让助手知道要在主进程代码中搜索哪个名称。下面四段代码展示这条调用链。
四段简短代码
从打包的JavaScript简化,具有可读的变量名称。 不相关的成员被省略。
-
从公开到页面的API开始
tab_browser_view/preload.js · API 成员const clipboardApi = { write: invokerInMain("notion:clipboard:write") }; // Included in the API exposed through contextBridge: // window.__electronApi.clipboard此成员提供通道名称。 的实施
invokerInMain告诉我们请求如何离开页面的进程。 -
解析预加载的包装器
tab_browser_view/preload.js · IPC 辅助函数function invokerInMain(channel) { return (...args) => invokeInMainAndReturnResult(channel, ...args); } function invokeInMainAndReturnResult(channel, ...args) { return ipcRenderer.invoke(channel, ...args); }返回的函数通过 Electron 的请求/响应 IPC 转发参数。接下来可以在主进程中查找
notion:clipboard:write。 -
检查接收器是如何注册的
主要/index.js · 处理程序助手const handleRequestFromRenderer = { addListener(channel, handler) { ipcMain.handle(channel, handler); } };主进程使用另一个包装器。 其
addListener方法注册一个ipcMain.handle那个频道的接收器。 -
查找写入及其发件人检查
主要/index.js · 剪贴板接收器handleRequestFromRenderer.addListener( "notion:clipboard:write", (event, data) => isNotionWebContents(event.sender) ? clipboard.write(data) : undefined );这就是调用的终点。处理函数检查发送方后,把收到的数据交给 Electron 的剪贴板 API。通道名和两个解析后的包装函数,把暴露给页面的方法连接到了这里。
复制的块如何保持其结构?
Notion 的网页编辑器通过 electronApi.clipboard.write 发送文本和 HTML。它在本地保留内容块数据,再在复制的 HTML 中放入一个 ID,将二者关联起来。
保存的块数据的HTML链接
text: "Project notes"
html: "<p>Project notes</p>"
+ "<!-- notionvc: <copy-id> -->"
id: <copy-id>
mimeTypes:
text/_notion-blocks-v3-production
→ structured block data
- 读取HTML ID
- 查找相同的本地ID
- 恢复Notion块数据
在粘贴时,Notion查找HTML ID并根据保存的复制进行检查。 匹配的Id恢复所述块数据。
从2026年7月13日缓存的web资产中记录的剪贴板格式。
更多示例和来源
另一个例子:Markdown 表格
Notion将Markdown解析为块数据。 此示例显示表如何成为标题和数据行。
通过Notion的Markdown解析器的表格
| A | B |
| - | - |
| 1 | 2 |
table · headerRow: true
table_row
cells: ["A"], ["B"]
table_row
cells: ["1"], ["2"]
另一条路径:脱机SQLite连接
Notion 的渲染进程通过 IPC 请求 getSqliteMeta。主进程创建消息通道,把一个端口交给渲染进程,另一个交给 SQLite 工具进程。后续的语句批次和结果直接通过这个端口传输。
追踪这次交接,就能知道数据库操作在哪个进程执行,也能解释为什么只跟踪最初的 IPC 请求会漏掉后续通信。
资料来源及如何阅读摘录
剪贴板桥接代码来自 Notion Desktop 7.6.1 的 app.asar,包括标签页预加载脚本和 main/index.js。节选中展开了压缩后的变量名,并省略无关代码;发送方检查辅助函数展示了底层的 isNotionWebContents 调用。
虚拟剪贴板和 Markdown 示例来自 2026 年 7 月 13 日缓存的网页资源,包括 747001、58169、736810 和 422457 模块。这些资源有独立版本。保存的测试执行提取出的模块和小型测试程序;输出反映的是这些测试,没有记录桌面 UI 操作。
这里的 REA 结果是对保存的标签页预加载脚本进行的专项分析,使用已发布的 REA 4.1.0 记录。它定位了 API 和调用操作。读取包中的包装函数实现后,就能把剪贴板成员与匹配的接收方连接起来。
Markdown 示例使用解析器模块 422457。保存的模块测试显示,页面和聊天过滤器都会保留这张表格。粘贴/导入、结构化标记和 AI/聊天解析器各自有不同入口与中间格式。
- JavaScript应用指南遵循一个小的Electron应用程序的导出功能。
- DX-Ball 重建工程按照原生说明检查c函数。