前端富文本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 仓库中packages/xl-odt-exporter/src/odt/template/模板目录展开说明 ODTOpenDocument Text导出器如何以一份由 LibreOffice 生成的演示文档为模板、并最终只消费其中的styles.xml的完整设计。读完本文你将掌握 ODT 导出包内部的文件结构、模板的由来与格式化策略、以及导出器基于 React 与 zip.js 组装 ODF 文档的底层实现。模板目录是什么一份被拆开的 ODT 文件ODFOpenDocument本质上是一个 ZIP 容器里面装着若干 XML 与二进制资源。BlockNote 的 ODT 导出器并不从零手写整套 ODF 样式体系而是先让 LibreOffice 生成一份样板文档再把它解压、格式化后放进仓库作为模板。模板目录packages/xl-odt-exporter/src/odt/template/中的README.md明确记录了三条关键信息template blocknote.odt是演示 docx 导出的产物它源自仓库中将块转换为 docx的示例对应 examples/05-interoperability/06-converting-blocks-to-docx先在 Mac 上用 LibreOffice 打开该 docx再另存为 ODT得到。解压出的文件都经过了格式化用 VS Code 的 XML 格式化器重新排版目的是让跨提交的 diff 可读——未格式化的 LibreOffice XML 通常是单行超长文本无法进行版本对比。styles.xml是导出器唯一实际使用的文件其余文件content.xml、meta.xml、settings.xml等只是模板工作流的副产品导出器运行时会重新生成自己的版本。这一以真实办公软件产物为模板的做法保证了导出的 ODT 在 LibreOffice/Word 中的样式基线字体、段落、标题、列表、边框等与真实文档一致而不是导出器闭门造车。模板目录结构逐文件解析解压template blocknote.odt后得到如下结构packages/xl-odt-exporter/src/odt/template/ ├── META-INF/ │ └── manifest.xml # ODF 包内文件清单模板自身版本 ├── Pictures/ │ └── 100000000000014C0000014CDD284996.jpg # 模板内嵌的演示图片 ├── Thumbnails/ │ └── thumbnail.png # 文档缩略图 ├── content.xml # 文档正文430 行模板自身版本 ├── manifest.rdf # RDF 元数据 ├── meta.xml # 文档元信息 ├── mimetype # 固定文本application/vnd.oasis.opendocument.text ├── settings.xml # 编辑器视图设置 ├── styles.xml # 样式定义1078 行导出器唯一消费的文件 └── template blocknote.odt # 原始 ODT 二进制ODF 规范要求 ZIP 包内第一个条目必须是mimetype且不压缩存储——这是所有 ODF 阅读器识别文件类型的依据。模板目录完整保留了这一约定而导出器在运行时也会严格遵守见下文。从 manifest.xml 可以看到模板自带的清单声明了content.xml、styles.xml、Pictures/等全部条目这份清单同样是模板自身版本导出时会用动态生成的 manifest 取代它。styles.xml导出器唯一真正消费的模板资产README.md强调的第三点在源码中得到直接印证odtExporter.tsx 第 17 行 通过 Vite 的?raw导入把模板中的styles.xml以纯文本方式打进产物import stylesXml from ./template/styles.xml?raw;随后在toODTDocument的打包阶段这段 XML 原样写入 ZIP 包void zipWriter.add(styles.xml, new TextReader(stylesXml));也就是说无论用户文档包含多少块、多少样式styles.xml始终是模板里那份固定的 1078 行文件它提供了默认字体声明Inter 18pt、Geist Mono、PingFang SC 等、style:default-stylegraphic / paragraph / text 三类默认样式、标题样式Heading_20_1~Heading_20_6、列表样式WWNum1、No_20_List、代码块样式Codeblock、Caption、PageBreak、Internet_20_link等命名样式。从源码结构可以推断其分工静态命名样式标题、列表、链接、代码块、页眉页脚等由styles.xml预先定义动态自动样式由用户块属性生成由导出器在运行时写入content.xml的office:automatic-styles节两者互不干扰。这也是模板 运行时生成双轨设计模板负责稳定的排版基线运行时负责逐文档的个性化属性。导出器如何组装一个合法的 ODT 包ODTExporter继承自blocknote/core的Exporter基类核心方法toODTDocumentodtExporter.tsx L190-L375用zip.js/zip.js的ZipWriter按顺序写入条目mimetype第一项compressionMethod: 0不压缩值固定为application/vnd.oasis.opendocument.text严格遵循 ODF 规范content.xml由 React 组件树经renderToString序列化得到office:document-content office:version1.3内含office:font-face-decls、office:automatic-styles、可选的office:master-styles页眉/页脚与office:bodystyles.xml来自模板的?raw导入META-INF/manifest.xml动态生成的清单声明根条目、content.xml、styles.xml以及随后追加的每张图片、每个字体与每个嵌入对象Fonts/*loadFonts从shared/assets/fonts/载入 Inter 18pt 与 Geist Mono 两个 TTF写入Fonts/目录并在font-face-decls中声明Pictures/*图片经registerPicture注册后按Pictures/picture-N.ext命名写入Object N/content.xml公式等嵌入对象的子文档见下文。页眉页脚与命名空间清理toODTDocument的第二个参数支持传入header/footer字符串或XMLDocument。传入的 XML 会经xmlOptionToString处理用正则剥离掉已在根元素声明过的重复命名空间声明再注入style:master-page style:nameStandard的style:header/style:footer中。对应测试见 odtExporter.test.ts 的 should export a document with custom document options。自动样式注册与去重BN_S / BN_T 命名空间ODF 的样式分为命名样式与自动样式两类。导出器对由块属性临时派生的样式通过registerStyleodtExporter.tsx L377-L391注册到office:automatic-styles样式名形如BN_S{n}段落/表格等按注册顺序自增按渲染形状去重以占位符名字渲染出样式定义、用JSON.stringify作为键存入registeredStyleNames相同定义复用同一名字——否则一份多段落文档会把 automatic-styles 塞满重复拷贝内联文本样式同理transformStyledText以T:前缀的键去重命名BN_T{n}odtExporter.tsx L128-L139。测试 “deduplicates identical automatic styles” 验证了同一 italic 定义两次注册返回相同名字、italic 与 bold 返回不同名字。块级样式的生成集中在 blocks.tsx 的createParagraphStyle把 BlockNote 的textAlignmentleft/center/right/justify映射为fo:text-align的 start/center/end/justify把backgroundColor/textColor通过exporter.options.colors默认COLORS_DEFAULT解析成十六进制色值全部属性为空时直接回退到父样式Standard避免产生无意义的新样式。引用块、分隔线则通过参数注入fo:border-left、fo:border-top等属性形成视觉样式。图片、字体与嵌入对象registerPictureodtExporter.tsx L417-L462负责图片资源同一 URL 幂等picturesMap 缓存重复引用复用同一文件用resolveFileUrl拉取图片默认corsProxyResolveFileUrl走 CORS 代理与 pdf/docx 导出器一致依据 Blob 的 MIME 类型推断扩展名apng/avif/bmp/gif/ico/jpg/png/svg/tiff/webp未知回退 png用getImageDimensions读取原始像素尺寸供draw:frame的svg:width/svg:height使用。registerObjectodtExporter.tsx L408-L415支持公式等嵌入对象注册后返回Object N/路径导出时写入Object N/content.xml子文档并在 manifest 中声明其 media-type默认application/vnd.oasis.opendocument.formula块映射中可通过draw:object的xlink:href引用。默认 Schema 映射块到 ODF 的翻译defaultSchema/index.ts 汇出odtDefaultSchemaMappings由 blocks.tsx块映射、inlineContent.tsx行内内容、styles.ts样式映射组成。关键翻译规则包括段落/标题/引用映射为text:p/text:h嵌套层级用text:tab前缀缩进getTabs列表每个列表项各自包一层text:list注释说明这是与 Word DocX→ODT 导出一致的做法LibreOffice 打开后会自行合并为同一列表编号列表通过text:continue-numbering与text:start-value延续编号待办项用☒/☐前缀文本表示勾选状态折叠项用前缀分页符输出带PageBreak样式的空段落表格列宽以 px×0.75 换算为 ptstyle:rel-column-width处理多列布局合并单元格遵循 ODF 模型——跨越单元格带table:number-columns/rows-spanned被覆盖的网格位置必须补table:covered-table-cell/blocks.tsx L511-L564 的网格扫描逻辑图片/文件/视频/音频无 URL 的未上传占位符不是文档内容导出为空有 URL 的媒体输出为Internet_20_link链接dictionary.open_file等文案多列复用blocknote/xl-multi-column的 schema渲染为 ODF 表格行内样式styles.tsbold→fo:font-weight: bold、italic→fo:font-style: italic、underline→style:text-underline-style: solid、strike→style:text-line-through-style: solid、textColor/backgroundColor→fo:color/fo:background-color、code→style:font-name: Courier New。测试与快照验证模板工作流的闭环odtExporter.test.ts用testDocumentshared/testDocument.ts构造覆盖多类块的文档经testODTDocumentAgainstSnapshot与__snapshots__/basic/、__snapshots__/withCustomOptions/下的content.xml/styles.xml快照对比验证了基础导出包含自动样式、图片、表格等元素的文档能稳定生成合法 ODF自定义页眉页脚toODTDocument的 options 生效样式去重同一渲染形状的样式只注册一次。快照与模板目录中格式化的 XML 一脉相承——正是用 VS Code XML 格式化器排版、保证 diff 可读策略在测试侧的延续。小结模板目录的设计哲学回顾template/README.md的三条结论可归纳出 ODT 导出器模板设计的三点核心以真实产物为起点用 LibreOffice 打开官方 docx 演示再另存为 ODT确保样式基线贴近主流办公软件的渲染结果格式化留痕解压出的 XML 统一格式化让模板的每次演进都能通过 git diff 审查最小消费1078 行的styles.xml是唯一被?raw导入并原样写入导出包的模板资产其余文件content.xml、meta.xml、manifest.rdf、settings.xml、Thumbnails 等仅作为工作流见证保留在目录中。如果要在 BlockNote 基础上定制 ODT 导出最实用的入口正是修改 template/styles.xml 中的命名样式如默认字体、标题颜色、列表符号或扩展 blocks.tsx 的块映射修改后跑pnpm test见 package.json即可用快照校验输出是否符合预期。赞分享前端富文本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 文档导出 ODTOpen Document Text完整实战指南从编辑器到可下载的 .odt 文件BlockNote 文档导出 ODTOpen Document Text完整实战指南从编辑器到可下载的 .odt 文件 导读 本指南围绕 BlockNot前端富文本UI组件AI 应用BentoPDF Word to PDF 转换工具全解析浏览器内 LibreOffice WASM 引擎下的 DOCX/DOC/ODT/RTF 转换指南BentoPDF Word to PDF 转换工具全解析浏览器内 LibreOffice WASM 引擎下的 DOCX/DOC/ODT/RTF 转换指南 Be前端突破文档预览瓶颈kkFileView集成LibreOffice实现Markdown到ODT无缝转换突破文档预览瓶颈kkFileView集成LibreOffice实现Markdown到ODT无缝转换 在日常办公和开发中你是否遇到过这些问题上传的Markd后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
以沟通记录为主线的CRM设计:DeskcommCRM实践与落地复盘 前阵子一个做企业服务的创始人找我聊,说他们公司买了一年 CRM,销售团队基本不登,客户信息还躺在 Excel 里。我问他销售打开系统第一眼看到的是什么,他愣了一下说:一堆要填的字段。这个场景我太熟了——绝大多数 CRM 不… · 2026/9/25 10:34:59
从进程到虚拟线程:一次讲透Java并发编程的核心线程体系 写完这篇,花了我挺长时间,但想到当年自己也是这么一路踩坑过来的,还是决定把整个思路完完整整地整理出来。希望对正在入门的你有帮助。线程这东西,刚接触并发编程的人多少都会有点懵。我自己刚入行那会儿,写过不少单线… · 2026/9/25 10:34:53
SSE流式+工具循环:Libraries.dev的Studio Agent后端架构与成本控制设计 SSE流式工具循环:Libraries.dev的Studio Agent后端架构与成本控制设计 【免费下载链接】Libraries.dev High-crafted UI libraries for AI agents: Border beam, Orbs, Metal, Gooey, Voice, Image, Avatar bots 项目地址: https://gitcode.com/gh_mirrors/bo/Lib… · 2026/9/25 10:34:29
NumPy傅里叶变换API从入门到实战:频谱分析与工程避坑指南 如果你做过信号处理、故障诊断或者图像分析,大概率绕不开 NumPy 的傅里叶变换接口——也就是numpy.fft那一组 API。我最开始在项目里用到它们,是因为需要从一段振动传感器数据里找出异常频率。当时我还不太明白原理,只知道调用np.fft.fft能得… · 2026/9/25 11:04:32
深圳售后完善的购物中心管理系统品牌企业实力参考 选购物中心管理系统必踩的4大常见坑很多购物中心、商管公司在选型数字化管理工具时,很容易掉进这些共性误区里:
怕选到功能适配差的系统:比如买了全链路方案却没法适配自身商圈的多业态布局,零售和餐饮商户不能共用一套系统&#… · 2026/9/25 11:04:26
力扣128最长连续序列:哈希表如何将复杂度优化到O(n) 在力扣刷题的过程里,128“最长连续数列”属于那种让人印象特别深的题目。它表面上看是一个数组遍历的问题,可实际上考察的是对时间复杂度的敏锐程度、对数据结构的选择,以及面对数字集合时能不能跳出“排序惯性”的思维定式。这道题被归类为中… · 2026/9/25 11:04:26
Wireshark抓包入门到实战:过滤器、TCP分析与安全体检 不少刚开始接触Wireshark抓包的朋友,第一天的体验基本都一样:软件装好了,兴奋地选中网卡,点下开始按钮,眼睁睁看着数据包像水龙头一样哗哗滚动,然后脑子一片空白。这不是因为你笨,而是还没建立起… · 2026/9/25 11:04:26
集中分拨保税物流服务商联系电话直联,欣进物流方案定制省心 什么是集中分拨保税物流:核心属性与应用基础科普集中分拨保税物流,是依托保税区域的政策与仓储资源,将多批次、多来源、多客户的保税货物集中存储分拣后,再统一配送到终端需求点的保税物流模式,是当前进出口贸易、品牌… · 2026/9/25 11:04:20
移动推荐算法竞赛实战:从数据切分到特征工程的完整代码解析 简介:本资源为阿里移动推荐算法竞赛的完整参赛代码与解析资料包,面向人工智能、数据挖掘及计算机相关专业的学生、教师与科研人员,尤其适合以推荐系统为课题的毕业设计、课程项目或竞赛复现场景。包内共190个文件,以Python源码为核… · 2026/9/25 11:04:20
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37