拓冰建站拓冰建站
首页 / 资讯中心 / 正文

使用 docx 库在 Word 文档中添加批注:Comments API 完整实战指南

使用 docx 库在 Word 文档中添加批注Comments API 完整实战指南【免费下载链接】docxEasily generate and modify .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.项目地址: https://gitcode.com/GitHub_Trending/do/docx本指南讲解如何在docxJS/TS 生成与修改 .docx 文件的声明式 API 库中使用 Comments 模块为文档中的指定文本范围添加类似 Microsoft Word 审阅功能的批注comments并覆盖回复线程threading与已解决resolved状态等高级能力。读完本文你将掌握从定义批注到锚定文本范围再到导出带批注文档的完整流程并能利用parentId构建多级讨论线程。前置知识批注依赖对 Sections节 与 Paragraphs段落 的理解建议先阅读这两篇文档再继续。批注的核心思想在docx中批注由定义与锚点两部分组成在Document的comments块中集中定义所有批注每条批注拥有唯一的id在正文段落中使用CommentRangeStart、CommentRangeEnd、CommentReference标记批注的呈现位置。也就是说批注的内容谁写的、写什么、什么时间写的与批注的位置覆盖哪段文字是分离声明的这与 OOXMLOffice Open XML标准中comments.xml与正文锚点分离的设计一脉相承。基础批注给一段文本添加批注下面的代码创建一条批注并把它挂到一段文本上import { Comment, CommentRangeEnd, CommentRangeStart, CommentReference, Document, Paragraph, TextRun } from docx; const doc new Document({ comments: { children: [ new Comment({ id: 0, author: John Smith, date: new Date(), children: [new Paragraph(This needs to be reviewed.)], }), ], }, sections: [ { children: [ new Paragraph({ children: [ new TextRun(This is normal text. ), new CommentRangeStart(0), new TextRun(This text has a comment.), new CommentRangeEnd(0), new CommentReference(0), ], }), ], }, ], });观察上面的结构CommentRangeStart(0)与CommentRangeEnd(0)把 This text has a comment. 这段文字圈起来CommentReference(0)则作为批注标记放在范围结束之后。三者使用同一个id与comments.children中的定义关联。底层 XML 长什么样从源码看这三个锚点类分别序列化为三个 WordprocessingML 元素见 src/file/paragraph/run/comment-run.tsCommentRangeStart(id)→w:commentRangeStart w:id0/CommentRangeEnd(id)→w:commentRangeEnd w:id0/CommentReference(id)→w:commentReference w:id0/它们都只承载一个必填的w:id属性对应的 XSD 类型为CT_MarkupRange需要十进制数字ST_DecimalNumber。而批注本体Comment则序列化为w:comment携带w:id、w:initials、w:author、w:date四个属性其中日期通过date.toISOString()输出为 ISO 8601 字符串。这些映射关系在 comment-run.spec.ts 的单元测试中有精确断言例如new CommentRangeStart(0) // → { w:commentRangeStart: { _attr: { w:id: 0 } } }Comment 选项详解new Comment({...})支持的完整选项如下属性类型必填说明idnumber是唯一标识符用于与正文锚点RangeStart/RangeEnd/Reference关联authorstring否批注作者名dateDate否批注时间戳不传时默认取new Date()源码默认值initialsstring否作者姓名缩写childrenParagraph[]是批注正文内容parentIdnumber否父批注的 ID用于构建回复线程resolvedboolean否是否将该批注线程标记为已解决在线程的任意一条批注上设为trueWord 中整个线程都会显示为已解决补充说明children中传入的可以是new Comment({...})实例也可以是普通对象字面量如{ id: 0, author: ..., children: [...] }两种形式完全等价源码中ICommentsOptions.children的类型就是readonly ICommentOptions[]。initials对应 OOXML 中的w:initials属性在 Word 批注面板中会显示为作者缩写。从源码的ICommentOptions类型定义src/file/paragraph/run/comment-run.ts看所有选项均为可选加readonly修饰id与children之外的字段在语义上是可选元数据。点状批注Point Comment如果不需要覆盖一段文本范围而只想在某个位置打一个批注标记可以只用CommentReferencenew Paragraph({ children: [ new TextRun(Check this point), new CommentReference(0), // Comment appears here ], });此时批注气泡会锚定在CommentReference所在的位置。这也是源码文档注释中明确提到的用法CommentReference元素放置在 run 内部用于建立指向某条批注的链接通常放在CommentRangeEnd之后。多个批注同一份文档中可以添加多条批注只需保证每条id唯一即可const doc new Document({ comments: { children: [ new Comment({ id: 0, author: Alice, date: new Date(2024-01-15), children: [new Paragraph(First comment)], }), new Comment({ id: 1, author: Bob, date: new Date(2024-01-16), children: [new Paragraph(Second comment)], }), ], }, sections: [ { children: [ new Paragraph({ children: [ new CommentRangeStart(0), new TextRun(Text with first comment.), new CommentRangeEnd(0), new CommentReference(0), new TextRun( ), new CommentRangeStart(1), new TextRun(Text with second comment.), new CommentRangeEnd(1), new CommentReference(1), ], }), ], }, ], });多条批注甚至可以锚定在同一段文字上——此时只需在段落中依次叠放多个CommentRangeStart再按对应顺序放置CommentRangeEnd与CommentReference这一模式在后面的回复线程中也会用到。回复线程Reply Threads使用parentId属性可以把批注组织成对话线程。一个关键注意事项回复批注同样必须用CommentRangeStart、CommentRangeEnd、CommentReference包裹与父批注相同的文本。Word 依靠这些锚点把每条批注挂到文档文字上如果缺失批注将没有可见锚点甚至可能被 Word 丢弃。const doc new Document({ comments: { children: [ { id: 0, author: Alice, date: new Date(2024-01-15), children: [new Paragraph(Is this correct?)], }, { id: 1, author: Bob, date: new Date(2024-01-16), parentId: 0, // This is a reply to comment 0 children: [new Paragraph(Yes, I verified it.)], }, { id: 2, author: Alice, date: new Date(2024-01-17), parentId: 0, // Another reply to comment 0 children: [new Paragraph(Thanks for checking!)], }, ], }, sections: [ { children: [ new Paragraph({ children: [ new CommentRangeStart(0), new CommentRangeStart(1), new CommentRangeStart(2), new TextRun(Text with a comment thread.), new CommentRangeEnd(0), new TextRun({ children: [new CommentReference(0)] }), new CommentRangeEnd(1), new TextRun({ children: [new CommentReference(1)] }), new CommentRangeEnd(2), new TextRun({ children: [new CommentReference(2)] }), ], }), ], }, ], });线程在 OOXML 中是如何落地的回复线程并不是简单的元数据它需要额外生成一个word/commentsExtended.xml部件。从源码实现看src/file/paragraph/run/comment-run.ts 与 src/file/paragraph/run/comments-extended.tsComments容器会检测children中是否出现parentId一旦出现即为所有批注生成 8 位大写十六进制的paraId规则是(id 1).toString(16).toUpperCase().padStart(8, 0)见工具函数commentIdToParaId例如id: 0→00000001、id: 1→00000002。序列化阶段Comment.prepForXml会把w14:paraId与w14:textId注入到批注内容最后一个段落的属性中仅当存在段落子元素时纯表格或无段落内容的批注不会注入对应测试用例已覆盖。Comments暴露ThreadData属性Documentsrc/file/file.ts据此创建CommentsExtended生成commentsExtended.xml其中每个w15:commentEx携带w15:paraId、w15:paraIdParent、w15:done属性分别表达自身段落 ID父段落 ID是否已解决同时注册commentsExtended的 relationship 与 Content Type。也就是说parentId与resolved的正确渲染依赖这份扩展部件wml-2012.xsd仓库 ooxml-schemas/microsoft/wml-2012.xsd中定义了CT_CommentsEx/CT_CommentEx的对应结构。相关行为在 comment-run.spec.ts 中有充分验证例如仅使用parentId时ThreadData产生{ paraId, parentParaId }映射线程激活时序列化结果中包含w14:paraId:00000001与w14:textId:00000001无线程时不会注入w14:paraId。已解决批注Resolved Comments使用resolved属性可以把整个线程标记为已解决。只要线程中任意一条批注设置resolved: trueWord 就会把整条线程显示为已解决状态为了语义清晰建议把该属性设置在根批注上comments: { children: [ { id: 0, author: Charlie, date: new Date(2024-01-15), resolved: true, // Marks the entire thread as resolved children: [new Paragraph(This timeline needs updating.)], }, { id: 1, author: Diana, date: new Date(2024-01-16), parentId: 0, children: [new Paragraph(Done - updated the dates.)], }, ], }在底层resolved会被映射为commentsExtended.xml中w15:commentEx的w15:done属性true→1false→0这一点可以从 comments-extended.ts 的序列化逻辑与对应单测resolved: true映射到ThreadData[].done true得到印证。富文本批注批注正文由普通Paragraph构成因此可以复用段落/文本的全部格式化能力——加粗、斜体、多段落等new Comment({ id: 0, author: Reviewer, children: [ new Paragraph({ children: [new TextRun({ text: Important: , bold: true }), new TextRun(Please verify the figures in this section.)], }), new Paragraph(See page 12 of the source document.), ], });甚至可以更进一步演示代码 demo/73-comments.ts 展示了批注内同时包含图片ImageRun读取demo/images/cat.jpg、换行文本与加粗文本的混合排版。这印证了children的类型是readonly FileChild[]——凡是能在正文中使用的子组件原则上都能放进批注。完整示例带审阅批注的报告文档综合以上所有特性一个完整可运行的示例import { Comment, CommentRangeEnd, CommentRangeStart, CommentReference, Document, HeadingLevel, Packer, Paragraph, TextRun } from docx; import * as fs from fs; const doc new Document({ comments: { children: [ new Comment({ id: 0, author: Editor, date: new Date(), children: [new Paragraph(Consider rephrasing this for clarity.)], }), new Comment({ id: 1, author: Fact Checker, date: new Date(), children: [ new Paragraph({ children: [new TextRun({ text: Verified , bold: true }), new TextRun(- Source: Annual Report 2023)], }), ], }), ], }, sections: [ { children: [ new Paragraph({ text: Quarterly Report, heading: HeadingLevel.HEADING_1, }), new Paragraph({ children: [ new TextRun(Our ), new CommentRangeStart(0), new TextRun(company achieved remarkable growth), new CommentRangeEnd(0), new CommentReference(0), new TextRun( this quarter. ), new CommentRangeStart(1), new TextRun(Revenue increased by 25%), new CommentRangeEnd(1), new CommentReference(1), new TextRun( compared to last year.), ], }), ], }, ], }); Packer.toBuffer(doc).then((buffer) { fs.writeFileSync(document.docx, buffer); });运行后将生成document.docx在 Word 中打开company achieved remarkable growth 与 Revenue increased by 25% 两处会显示批注气泡分别来自 Editor 与 Fact Checker。该示例也可以在浏览器环境运行Packer同时支持 Node 与 Browser与仓库描述 Works for Node and on the Browser 一致。参考演示代码仓库中提供了两份与本文直接对应的可运行演示demo/73-comments.ts基础批注用法包含四条批注含批注内嵌图片、多段落、加粗文本并演示多个批注锚定同一段文字的写法demo/101-comment-replies.ts批注回复线程与 resolved 状态的完整演示——线程一id 0/1/2为活跃讨论线程二id 3/4为已解决线程正文分别用This text has active comments与This text has resolved comments展示两种状态。两份演示都通过Packer.toBuffer导出为My Document.docx可直接在本地运行验证npx ts-node demo/101-comment-replies.ts或在项目已配置的 TS 环境下执行后打开生成的文档在 Word 审阅窗格中即可看到线程与已解决标记。小结通过comments块 CommentRangeStart/End/Reference三件套docx把 Word 的审阅批注能力完整带入了声明式 API基础批注、点状批注、多批注、富文本批注随取随用parentId与resolved则在背后驱动commentsExtended.xml与w14:paraId机制实现线程与解决状态的完整呈现。理解这层 XML 映射关系能帮助你在批注与图片、表格、复杂段落混排时快速定位问题——相关的类型定义、序列化实现与测试用例分别位于 comment-run.ts、comments-extended.ts 与 comment-run.spec.ts可作为深入阅读的入口。【免费下载链接】docxEasily generate and modify .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.项目地址: https://gitcode.com/GitHub_Trending/do/docx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门