ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

BlockNote 剪贴板快照深度解析:跨父子边界选择(childrenToNextParent)的 Markdown 复制输出

BlockNote 剪贴板快照深度解析:跨父子边界选择(childrenToNextParent)的 Markdown 复制输出 前端富文本UI组件AI 应用【免费下载链接】BlockNoteA React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.项目地址https://gitcode.com/gh_mirrors/bl/BlockNote点击查看免费下载本篇文章以 BlockNote 仓库中 tests/src/unit/core/clipboard/copy/snapshots/text/plain/childrenToNextParent.md 这一测试快照文件为切入点围绕它所属的复制copy测试体系完整讲解 BlockNote 在用户选中嵌套子块 其后的兄弟父块这一跨父子边界范围时text/plain剪贴板数据Markdown 形式是如何生成的。读完本文你将掌握 BlockNote 复制测试的完整链路测试用例定义 → 编辑器初始化 → 选区构造 → 片段序列化 → 快照断言理解嵌套块复制时 Markdown 输出每块一行、块间空行分隔的底层原理并能够依据快照文件反推、验证 BlockNote 的复制行为。快照文件是什么一个 Markdown 剪贴板输出的黄金基准打开 childrenToNextParent.md文件内容非常简短Nested Paragraph 1 Nested Paragraph 2 Nested Paragraph 3 Paragraph 2它不是一个普通文档而是BlockNote 复制测试的期望输出快照snapshot当用户在编辑器内复制一段跨越嵌套层级的选择范围时写入系统剪贴板text/plain数据应恰好等于上述文本。快照文件由 vitest 的toMatchFileSnapshot断言自动比对见 copyTestExecutors.ts任何复制逻辑的改动导致输出变化测试都会失败并提示差异从而锁定剪贴板行为不被无意破坏。与它同目录的 HTML 快照 childrenToNextParent.html 记录了同一选择范围在text/html剪贴板中的数据pNested Paragraph 1/p pNested Paragraph 2/p pNested Paragraph 3/p pParagraph 2/pHTML 与 Markdown 两种快照一一对应共同构成同一选区、多格式输出的验证矩阵。测试用例定义childrenToNextParent 的文档与选区快照对应的测试用例定义在 copyTestInstances.ts 中名为childrenToNextParent。它先用PartialBlock数组描述测试文档结构{ testCase: { name: childrenToNextParent, document: [ { type: paragraph, content: Paragraph 1, children: [ { type: paragraph, content: Nested Paragraph 1 }, { type: paragraph, content: Nested Paragraph 2 }, { type: paragraph, content: Nested Paragraph 3 }, ], }, { type: paragraph, content: Paragraph 2, }, ], getCopySelection: (doc) { const startPos getPosOfTextNode(doc, Nested Paragraph 1); const endPos getPosOfTextNode(doc, Paragraph 2, true); return TextSelection.create(doc, startPos, endPos); }, }, executeTest: testCopyHTML, }该文档对应一棵典型的 Notion 风格嵌套树顶级块Paragraph 1父块内含三个子块Nested Paragraph 1/2/3顶级块Paragraph 2父块的兄弟块。选区selection跨越了父子边界起点是第一个嵌套子块Nested Paragraph 1的文本开头终点是顶级兄弟块Paragraph 2的文本末尾。这就是测试名 childrenToNextParent子块到下一个父块的含义——它专门验证选中内容同时覆盖某父块的多个子块与下一个父块本身这一场景确保复制出的块列表结构正确、顺序正确、不丢块。选区的定位依赖测试工具函数 getPosOfTextNode默认返回目标文本节点前的位置传true时返回节点之后的位置pos node.nodeSize以此构造TextSelection.create(doc, startPos, endPos)。该函数通过 ProseMirror 的doc.descendants遍历查找文本内容完全匹配的节点。测试执行管线从文档到快照的三步链路整个复制测试由 runTests.test.ts 驱动。它对copyTestInstancesHTML与copyTestInstancesMarkdown两组用例分别运行Copy tests (HTML)与Copy tests (Markdown)两组 describe。其中 Markdown 组的关键在于copyTestInstancesMarkdown并非重新定义文档而是直接复用 HTML 组的同一批测试用例仅把执行器换成testCopyMarkdown见 copyTestInstances.ts——同一选区在两种剪贴板格式下被分别验证。testCopyMarkdown执行器copyTestExecutors.ts的调用链如下export const testCopyMarkdown async (editor, testCase) { initTestEditor(editor, testCase.document, testCase.getCopySelection); const { markdown } selectedFragmentToHTML(editor.prosemirrorView, editor); await expect(markdown).toMatchFileSnapshot( ./__snapshots__/text/plain/${testCase.name}.md, ); };三个步骤环环相扣初始化编辑器与选区initTestEditor 重置 mock 块 ID 计数器__TEST_OPTIONS.mockID 0保证快照中块 ID 稳定可复现通过editor.replaceBlocks载入测试文档再在editor.transact事务中调用getCopySelection(tr.doc)设置选区生成剪贴板数据调用核心 APIselectedFragmentToHTML取出其中markdown字段快照断言toMatchFileSnapshot将实际输出与__snapshots__/text/plain/${name}.md比对即与本文主角childrenToNextParent.md比对。底层原理Markdown 剪贴板数据如何从选区产生selectedFragmentToHTML定义于 copyExtension.ts它一次生成三种剪贴板数据返回{ clipboardHTML, externalHTML, markdown }字段用途生成方式clipboardHTML写入blocknote/htmlBlockNote 内部格式ProseMirror 默认剪贴板序列化view.serializeForClipboardexternalHTML写入text/html外部通用 HTMLfragmentToExternalHTML走外部 HTML 导出器markdown写入text/plain纯文本由externalHTML经cleanHTMLToMarkdown转换其中markdown的生成遵循两条规则普通场景cleanHTMLToMarkdown(externalHTML)—— 先由外部 HTML 导出器把选中片段序列化为块级 HTML再转换为 Markdown纯代码块场景当选区完全位于meta.code true的块内如 codeBlock时直接取doc.textBetween($from.pos, $to.pos)的原始文本避免 Markdown 围栏fences和反斜杠转义残留注释见 copyTestInstances.ts。随后实际写入剪贴板的动作发生在 copyToClipboardevent.preventDefault()阻止浏览器默认行为依次setData(blocknote/html, clipboardHTML)、setData(text/html, externalHTML)、setData(text/plain, markdown)。因此本快照文件实质上就是用户按 Ctrl/CmdC 时系统剪贴板text/plain数据的精确还原。为何输出是每块一行 空行分隔markdown的生成链路是externalHTML → cleanHTMLToMarkdown。cleanHTMLToMarkdown 做了两件事移除EMPTY_BLOCK_PLACEHOLDER——外部 HTML 导出器会用占位字符填充空的内联内容块以保证 HTML 往返不丢块但 Markdown 不需要它必须剔除否则会出现幽灵字符源码注释明确说明这一点调用htmlToMarkdown把块级 HTML 转成 Markdown。对于本例这种全部由普通段落paragraph组成的选中范围p.../p会被转换为各自独立的 Markdown 段落段落之间以空行分隔于是得到快照中的 4 行文本 3 个空行。这里没有任何缩进或列表标记因为选中块均为顶层级别的普通段落——注意Nested Paragraph 1/2/3虽是Paragraph 1的子块但在 plain/text 序列化中它们被扁平化为独立的 Markdown 段落层级信息由块结构承载而非缩进符号表达。这正是 Markdown 剪贴板输出与文档树层级之间的关键差异点。横向对照相邻用例验证嵌套行为同目录下另两个快照可作为对照进一步验证跨父边界选择的序列化行为childrenToNextParentsChildren.md 对应 childrenToNextParentsChildren 用例Paragraph 2也有自己的三个子块Nested Paragraph 4/5/6选区覆盖全部六个子块加Paragraph 2输出为 7 段连续文本同样块间空行分隔childToParent.md 对应childToParent用例选区从父块Paragraph 1到第一个子块Nested Paragraph 1验证的是反向父到子边界。三个用例共同覆盖了子→子multipleChildren、父→子childToParent、子→下一个父childrenToNextParent、子→下一个父的子childrenToNextParentsChildren这四种嵌套选区组合构成完整的嵌套复制验证矩阵。如何运行与复现该快照验证快照所属测试运行在tests/工作区中。仓库采用 pnpm workspace 管理见 pnpm-workspace.yaml核心包为blocknote/corepackages/core测试通过 vite.config.ts 配置。可执行以下命令复现# 在仓库根目录安装依赖若尚未安装 pnpm install # 运行复制相关单元测试含 HTML 与 Markdown 两组快照断言 pnpm --filter blocknote/test run test -- src/unit/core/clipboard/copy运行后 vitest 会逐条执行runTests.test.ts中的用例将selectedFragmentToHTML实际生成的 markdown 与 childrenToNextParent.md 等快照比对。若复制逻辑发生变化导致输出与快照不一致测试会失败并生成.new后缀的差异文件便于开发者审查是否符合预期后再决定是否更新快照。结语从一行快照反推整个复制子系统childrenToNextParent.md表面上只是 7 行纯文本但它浓缩了 BlockNote 剪贴板子系统的一条完整验证链测试用例copyTestInstances.ts定义文档与跨父边界选区 → 执行器copyTestExecutors.ts初始化编辑器并调用核心 API → copyExtension.ts 的selectedFragmentToHTML产出三格式数据 → markdownExporter.ts 的cleanHTMLToMarkdown完成 HTML→Markdown 转换 → 快照锁定结果。阅读这类快照时建议始终对照其 HTML 同名快照与测试用例中的document/getCopySelection即可快速还原什么样的选区产生什么样的剪贴板输出这是理解 BlockNote 数据序列化行为最高效的入口。赞分享前端富文本UI组件AI 应用【免费下载链接】BlockNoteA React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.项目地址https://gitcode.com/gh_mirrors/bl/BlockNote点击查看免费下载相关推荐BlockNote 剪贴板复制测试深度解析text/plain 快照如何保证嵌套块复制后的 Markdown 输出BlockNote 剪贴板复制测试深度解析text/plain 快照如何保证嵌套块复制后的 Markdown 输出 BlockNote 在复制/剪切时会在剪贴前端富文本UI组件AI 应用BlockNote 嵌套块复制的剪贴板输出解析从 childrenToNextParentsChildren 测试快照看 text/plain Markdown 链路BlockNote 嵌套块复制的剪贴板输出解析从 childrenToNextParentsChildren 测试快照看 text/plain Markdow前端富文本UI组件AI 应用BlockNote 代码块部分选择的剪贴板复制text/plain 快照与源码级解析BlockNote 代码块部分选择的剪贴板复制text/plain 快照与源码级解析 BlockNote 是一款基于 ProseMirror 与 Tiptap前端富文本UI组件AI 应用上一篇如何快速获取抖音直播数据DouyinLiveWebFetcher完整实战指南下一篇Origami Simulator 实时折纸模拟从打开浏览器到折出立体模型创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表