docx 实战指南:用 `bullet` 属性在 JS/TS 中快速生成 Word 项目符号列表
2026/9/17 10:31:23 网站建设 项目流程

docx 实战指南:用bullet属性在 JS/TS 中快速生成 Word 项目符号列表

【免费下载链接】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

本文聚焦 docx 库中项目符号列表(Bullet Points)的完整用法:从最基础的bullet: { level: 0 }段落配置,到多级嵌套列表、程序化批量生成、与其他段落混排以及富文本样式定制,并深入仓库源码剖析 bullet 在 OOXML 层(w:numPr/w:ilvl/w:numId)的真实映射原理。读完本文,你将能独立用 docx 在 Node 或浏览器环境中生成任意结构的 Word 无序列表。

说明:Bullet Points 的实现依赖 Paragraph(段落)概念,建议先阅读 Paragraph 文档 建立基础。

基础用法:为段落添加bullet属性

在 docx 中,项目符号列表并不需要单独的数据结构,只需在Paragraph的配置对象中加上bullet属性即可。bullet是一个对象,目前只接受一个必填字段level(缩进层级):

import { Document, Paragraph } from "docx"; const doc = new Document({ sections: [ { children: [ new Paragraph({ text: "First item", bullet: { level: 0, }, }), new Paragraph({ text: "Second item", bullet: { level: 0, }, }), new Paragraph({ text: "Third item", bullet: { level: 0, }, }), ], }, ], });

生成效果(Word 中渲染为圆点列表):

  • First item
  • Second item
  • Third item

在 段落属性源码 中可以看到,bullet的类型定义极为精简:

readonly bullet?: { /** Indentation level for the bullet (0-8) */ readonly level: number; };

level唯一决定了项目符号的层级与缩进位置,这正是 docx 声明式 API 的特点——用最少配置表达常见需求。

多级列表:用不同level值构建嵌套结构

Word 支持最多 9 个列表层级(level取 0–9),通过给不同段落指定不同level,即可天然形成父子嵌套关系,无需手动管理缩进:

const doc = new Document({ sections: [ { children: [ new Paragraph({ text: "Main item 1", bullet: { level: 0 } }), new Paragraph({ text: "Sub-item 1.1", bullet: { level: 1 } }), new Paragraph({ text: "Sub-item 1.2", bullet: { level: 1 } }), new Paragraph({ text: "Deep item 1.2.1", bullet: { level: 2 } }), new Paragraph({ text: "Main item 2", bullet: { level: 0 } }), ], }, ], });

渲染效果:

  • Main item 1
    • Sub-item 1.1
    • Sub-item 1.2
      • Deep item 1.2.1
  • Main item 2

值得注意的是,docx 为bullet模式内置了完整的默认符号与缩进方案。在 numbering.ts 源码 中,Document初始化时会自动注册一个名为default-bullet-numbering的抽象编号定义,共配置 0–8 共 9 个级别,各级符号与缩进如下(来自仓库内真实配置):

level符号(Unicode)左缩进悬挂缩进
0\u25CF0.5 in0.25 in
1\u25CB1 in0.25 in
2\u25A02160 twip0.25 in
3\u25CF2880 twip0.25 in
4\u25CB3600 twip0.25 in
5\u25A04320 twip0.25 in
6\u25CF5040 twip0.25 in
7\u25CF5760 twip0.25 in
8\u25CF6480 twip0.25 in

符号在 ● / ○ / ■ 之间循环,缩进随层级递增(0.5 英寸起步,之后每级约增加 720 twip,1 twip = 1/20 磅)。也就是说,即使用户不配置任何编号方案,bullet也能直接产出规范的多级列表外观。

bullet选项参数速查

原文档给出bullet对象的唯一配置项:

PropertyTypeNotesDescription
levelnumberRequiredIndentation level (0-9)

结合源码补充两个关键细节:

  • 自动应用列表段落样式:当段落设置了bullet时,properties.ts 会自动为该段落注入ListParagraph段落样式,保证列表段落与正文段落有正确的行距与缩进基调;
  • 层级上限校验:在 unordered-list.ts 源码 中,IndentLevel构造器会对level > 9抛出错误(Level cannot be greater than 9),这与 Word 本身最多支持 9 级列表的限制一致;内置默认配置实际只定义到 8 级,超出后如需自定义符号样式,应改用numbering配置(见后文“相关主题”)。

程序化列表生成:从数组批量生成项目符号

实际项目中列表数据通常来自接口或配置,可以用Array.prototype.map一行生成多个 bullet 段落:

const items = ["Apple", "Banana", "Cherry", "Date"]; const doc = new Document({ sections: [ { children: items.map( (item) => new Paragraph({ text: item, bullet: { level: 0 }, }), ), }, ], });

渲染效果:

  • Apple
  • Banana
  • Cherry
  • Date

这种写法把“数据 → 段落”的转换完全函数化,适合搭配任意数据源(CSV、数据库查询结果、API 响应等)动态构建文档。

嵌套数据结构:递归生成层级列表

当数据本身具有树形结构(如菜单、目录、分类树)时,可以编写一个递归函数,每深入一层level + 1,即可自动映射为 Word 多级列表:

interface MenuItem { name: string; children?: MenuItem[]; } const menu: MenuItem[] = [ { name: "Fruits", children: [{ name: "Apple" }, { name: "Orange" }], }, { name: "Vegetables", children: [{ name: "Carrot" }, { name: "Broccoli" }], }, ]; function createBulletItems(items: MenuItem[], level: number = 0): Paragraph[] { const paragraphs: Paragraph[] = []; for (const item of items) { paragraphs.push( new Paragraph({ text: item.name, bullet: { level }, }), ); if (item.children) { paragraphs.push(...createBulletItems(item.children, level + 1)); } } return paragraphs; } const doc = new Document({ sections: [ { children: createBulletItems(menu), }, ], });

渲染效果:

  • Fruits
    • Apple
    • Orange
  • Vegetables
    • Carrot
    • Broccoli

注意递归函数返回的是扁平化的Paragraph[]数组,最终由 docx 根据level重建层级关系——这种“数据扁平、层级由 level 表达”的设计,让生成逻辑非常干净。

混合内容:Bullet 与标题、普通段落共存

文档中列表很少单独存在,通常与标题、说明文字穿插。docx 允许在同一个 section 的children数组里自由混排:

import { HeadingLevel } from "docx"; const doc = new Document({ sections: [ { children: [ new Paragraph({ text: "Shopping List", heading: HeadingLevel.HEADING_1, }), new Paragraph("Items to buy:"), new Paragraph({ text: "Milk", bullet: { level: 0 } }), new Paragraph({ text: "Bread", bullet: { level: 0 } }), new Paragraph({ text: "Eggs", bullet: { level: 0 } }), new Paragraph("Remember to check expiration dates!"), ], }, ], });

渲染效果:

Shopping List

Items to buy:

  • Milk
  • Bread
  • Eggs

Remember to check expiration dates!

由于列表与正文本质上都是Paragraph,混排时无需任何特殊处理;bullet只会作用于设置了该属性的段落,前后普通段落不受影响。

富文本列表项:对 bullet 段落应用文本样式

bullet只负责列表外观,列表项内部的文本格式由TextRun控制。将bulletchildren: TextRun[]组合,即可实现“项目符号 + 富文本内容”:

import { TextRun } from "docx"; new Paragraph({ bullet: { level: 0 }, children: [ new TextRun({ text: "Important: ", bold: true }), new TextRun("This item requires attention"), ], });

渲染效果:

  • Important:This item requires attention

TextRun支持 docx 提供的全部 run 级格式(加粗、斜体、字体、颜色、下划线等),这意味着列表项可以携带任意复杂的内联排版,例如在列表中嵌入超链接或特殊字符。

源码透视:bullet在 OOXML 中的真实映射

理解底层机制有助于排查自定义列表样式的问题。当段落设置bullet后,properties.ts 会调用:

if (options.bullet) { this.push(new NumberProperties(1, options.bullet.level)); }

即固定以numId = 1引用内置的default-bullet-numbering定义。NumberProperties的实现位于 unordered-list.ts,最终产出如下 OOXML 结构:

<w:numPr> <w:ilvl w:val="0"/> <w:numId w:val="1"/> </w:numPr>
  • w:numPr:段落的编号属性容器;
  • w:ilvl:列表层级(与bullet.level对应);
  • w:numId:编号实例 ID,bullet模式固定为1,指向内置的默认项目符号编号定义。

该结构的正确性有单元测试兜底,见 unordered-list.spec.ts:测试断言new NumberProperties(5, 9)会序列化为w:numPr下包含w:ilvl(val=9)与w:numId(val=5),并验证level > 9时构造函数抛出异常。

对于需要完全自定义符号(如使用特殊字符、图片符号、自定义缩进)的场景,应放弃bullet快捷属性,改用numbering配置——在Document上定义numbering.config,配合LevelFormat.BULLETtext字段实现,仓库中的 numbering.ts 源码 给出了自定义 bullet level 的典型写法。

完整可运行示例

仓库提供了同时演示编号列表(罗马数字、自定义符号)与多级 bullet 的完整脚本:demo/3-numbering-and-bullet-points.ts。该示例展示了:

  • 使用numbering.config定义两套自定义方案(my-crazy-numberingmy-unique-bullet-points);
  • 在同一 section 中混用bullet快捷属性与numbering引用(二者可自由切换,层级各自独立);
  • 在页眉Header与页脚Footer中同样可以使用列表段落;
  • 自定义 bullet 通过LevelFormat.BULLET配合任意 Unicode 字符(\u1F60\u00A5\u273F\u267A\u2603)实现个性化符号,并借助convertInchesToTwip精确控制各级缩进;
  • 最后通过Packer.toBuffer(doc)导出为My Document.docx

相关主题

  • Numbering(编号列表与自定义编号方案) —— 需要自定义列表符号、编号格式(罗马数字、字母等)或重启编号时使用;
  • Paragraph(段落格式) —— 理解段落属性、TextRun与对齐、缩进等基础;
  • Styling with JS(JS 样式定制) —— 通过样式系统为列表定义可复用的样式模板。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询