@quirekit/lit-docx-html 把 DOCX 渲染成随屏幕宽度重排的 HTML,适合在网页或 App 中展示由 Word 编写的内容,
例如用户协议、隐私政策和公告。它不分页,也不还原页面尺寸、字体和段落间距;快速开始中示例的“预览”就由它渲染。
pnpm add @quirekit/lit-docx-html
转换为 HTML
docxToHtml 在浏览器和 Node 中都可运行。在构建时转换,页面直接输出静态 HTML,浏览器不必加载解析器:
import { readFile } from "node:fs/promises";
import { docxToHtml } from "@quirekit/lit-docx-html";
const { html, outline, emphasis } = await docxToHtml(new Uint8Array(await readFile("agreement.docx")));
html:正文的 HTML 片段。文字与属性都已转义;链接只保留http、https、mailto与页内锚点,图片只保留内嵌的位图。outline:标题与条款,含锚点、层级、编号文字(如“第一条”“1.1”)和正文,可用来生成目录。emphasis:加粗或下划线的文字及其所在条款的锚点。协议通常用这种格式标出需要特别提示的条款,可以汇总展示。title:文档标题,取条款开始前第一行居中的文字或第一个标题。
条款编号
Word 自动编号的段落会在渲染时加上编号文字。很多协议的编号是直接输入的文字,例如“第三条”“一、”“(一)”“4.1”“(1)”“①”, 这些也会被识别为条款,进入目录并获得锚点,文字本身保持原样。
- 层级按各种编号写法在文档中第一次出现的先后决定:先出现“一、”再出现“第一条”时,条在章之下;反之亦然。 Word 编号与手工编号一起参与排序。
- 某种写法在全文只出现一次时(如“1.5 倍行距”)不当作条款;表格内的段落不当作条款。
outlineDepth控制目录列到第几级,默认 2;typedClauses: false关闭手工编号识别。
加粗或下划线只有在去掉条款号与 {{…}} 占位符后仍有至少 8 个文字时才计入 emphasis,加粗的条款号和下划线填空不会混入重点条款。
自定义渲染
renderers 按节点类型、markRenderers 按标记类型替换默认渲染。渲染函数返回 { tag, attrs, children }
与文字组成的树;返回 null 省略该节点,返回 undefined 使用默认渲染:
const { html } = await docxToHtml(bytes, {
renderers: {
// 编号条款渲染成带编号徽标的 section
paragraph: (node, context) => context.number
? { tag: "section", attrs: { class: "clause", id: context.anchor },
children: [{ tag: "b", children: [context.number] }, ...context.children()] }
: undefined,
// 不展示表格
table: () => null,
},
markRenderers: {
// 加粗文字统一标成重点
bold: (_mark, content) => ({ tag: "mark", attrs: { class: "key-term" }, children: content }),
},
});
渲染上下文提供 children()(已渲染的子节点)、fallback()(默认渲染结果)、number、anchor 与祖先节点。
节点类型与属性见 LitAST 节点模型。已解析的 LitAST 可以直接交给 renderLitDocx,再用 toHtml
序列化;解析时请使用 numberingMode: "flat-numbered-paragraphs",编号文字才能按 Word 的规则计算。
在 Vue 中使用
<script setup lang="ts">
import { ref } from "vue";
import { LitDocxView } from "@quirekit/lit-docx-html/vue";
defineProps<{ bytes: Uint8Array }>();
const agreed = ref(false);
</script>
<template>
<LitDocxView :source="bytes" @rendered="result => console.log(result.outline)" @read-end="agreed = true" />
</template>
source 接受 DOCX 字节或 LitAST;options 传入与上面相同的自定义渲染。read-end 在文档末尾第一次进入视口时触发,
可用于“阅读完毕后才能勾选同意”。
主题与静态页面
包内的 @quirekit/lit-docx-html/styles.css 是默认主题:作用于 .lit-docx 容器,颜色与字体都是 CSS 变量(如
--lit-docx-accent、--lit-docx-font),跟随系统深色模式,也可用 data-theme="light" 或 "dark" 固定。
LitDocxView 的根元素就是 .lit-docx。
构建时可以直接用命令生成完整页面:
npx lit-docx-html agreement.docx -o agreement.html --toc --key-terms --outline agreement.json
--toc 加入目录,--key-terms 加入重点条款,--fragment 只输出正文片段,--lang en 切换英文界面文字,
--outline 另存目录与重点条款的 JSON。在代码中可用 renderHtmlPage、renderToc、renderKeyTerms 组合同样的页面。
对比两个版本
协议更新后通常要告知用户改了什么。compareDocx 按段落、标题和表格行对比两个版本,返回新增、删除与修改,并标出所在条款:
import { compareDocx } from "@quirekit/lit-docx-html";
const changes = await compareDocx(oldBytes, newBytes);
// [{ kind: "added", clause: { number: "第二条", text: "个人信息" }, after: "…" },
// { kind: "modified", clause: { number: "第三条", text: "服务内容" }, before: "…按年收取。", after: "…按月收取。" }]
匹配时忽略手工输入的条款号,中间插入一条后,后面整体顺延的“第五条”“第六条”不会被当成修改。相邻的删除与新增
文字相似度达到 similarity(默认 0.4)时合并为一处修改。删除项标注旧版本中的条款,其余标注新版本中的条款。
许可
@quirekit/lit-docx-html 与 lit-docx 一样是 QuireKit 商业组件,适用相同的授权条款。