
简介html-docx-js 是一个轻量级开源 JavaScript 库专为前端开发者设计用于在浏览器环境中将 HTML 内容无缝转换为标准 DOCX 文档无需后端服务或 Office 依赖适用于报表导出、在线文档生成、教学材料一键下载等场景。资源包共28个文件含4个核心 JS 文件含主库 html-docx.js 及内部工具模块、5个 CoffeeScript 源码便于二次开发与调试、3个模板文件tpl支撑内容结构化嵌入以及 README、LICENSE、测试 HTML 与示例资源如 cat.jpg、sample.html整体仅160KB即下即用。已有4678人学习下载包内提供完整可运行测试环境testbed.html、构建脚本gulpfile.coffee、Bower/NPM 配置及多层级目录组织src/dist/assets便于理解 altchunks 原理、调试转换逻辑或集成进现有 Web 应用。1. html-docx-js 是什么不是“导出 Word”按钮而是浏览器里跑通 DOCX 生成链路的最小可信闭环你点过多少次网页上的「导出为 Word」十有八九它背后是服务端调用 Python 的 python-docx、Java 的 Apache POI或者干脆走 Office Online API——但 html-docx-js 不同。它是一套纯前端、零服务端依赖、不发请求、不上传 HTML 内容的 DOCX 构建方案核心能力是在浏览器内存中把一段合法 HTML含内联样式、表格、列表、图片 base64逐节点解析映射成 Open XML 标准结构再打包成 ZIP 容器即 .docx 文件本质最后触发 Blob 下载。它解决的不是「怎么让 Word 打开网页内容」这种模糊需求而是「某内部系统需在离线环境/高安全策略下由用户自主生成带格式的可归档报告」这一类刚性场景。适合前端工程师、低代码平台开发者、政企内网系统维护者——尤其当你被明确告知「不能调后端接口」「不能连外网」「必须保留所有样式细节」时html-docx-js 是目前社区验证度最高、源码可读性最强、调试路径最短的落地选择。它不承诺 100% 还原 Chrome 渲染效果但能守住语义结构h1→标题1、table→表格、img→内嵌图、基础样式font-size、color、text-align、分页逻辑page-break-before这三条底线。2. 从 npm install 到点击下载三步跑通最小可运行链路2.1 初始化项目并安装 html-docx-jshtml-docx-js 并非官方 Microsoft 维护库而是社区长期演进的轻量封装。当前稳定主力版本为2.3.0截至 2024 年中它已放弃对 IE 的支持专注现代浏览器的 Blob 和 ZIP 构建能力。注意它不提供 UMD 全局变量必须通过 ES Module 或 CommonJS 引入也不内置 polyfill若需兼容 Safari 14 或旧版 Edge需自行补Promise.allSettled和Array.from。# 推荐使用 npmyarn 同理 npm install html-docx-js2.3.0提示不要安装html-docx无-js后缀或docx功能重叠但 API 完全不同二者命名极易混淆但 html-docx-js 是唯一专注「HTML → DOCX」单向转换且文档最全的包。2.2 构造一个带样式的 HTML 片段非简单 divhtml-docx-js 对 HTML 的健壮性要求高于直觉——它不接受div stylemargin:20px这类纯 CSS 布局块而依赖语义化标签与有限内联样式组合。以下是一个经实测能 100% 转换的最小有效片段!-- 注意必须包裹在 body 内且 body 不能有 class/id -- body h1 styletext-align:center;color:#2c3e50;项目验收报告/h1 p styletext-indent:2em;line-height:1.6;本报告依据《XXX技术规范》第5.2条编制涵盖全部测试用例执行结果。/p table border1 stylewidth:100%;border-collapse:collapse; thead trth stylebackground:#3498db;color:white;模块/thth stylebackground:#3498db;color:white;状态/th/tr /thead tbody trtd登录认证/tdtd✅ 通过/td/tr trtd数据导出/tdtd⚠️ 部分超时/td/tr /tbody /table p附图br img srcdata:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5hHgAHggJ/PchI7wAAAABJRU5ErkJggg alt性能趋势图 width400 height250 /p /body逻辑说明body是强制根容器库会忽略其外所有内容table必须带border1否则边框丢失img必须为 base64 内联图不支持srchttps://...外链因浏览器同源策略限制p的text-indent和line-height可被识别但margin-top会被忽略——这是 Open XML 段落间距模型与 CSS 的根本差异需提前接受。2.3 调用 convertHtmlToDocx 并触发下载核心函数convertHtmlToDocx()接收 HTML 字符串和可选配置对象返回PromiseBlob。关键参数只有两个orientation页面方向和margins页边距单位毫米。其他如字体、标题样式均通过 HTML 内联样式控制。import { convertHtmlToDocx } from html-docx-js; // 1. 获取上一步构造的 HTML 字符串实际项目中可能来自富文本编辑器 const htmlContent document.querySelector(#report-container).innerHTML; // 注意必须确保 htmlContent 是纯字符串不含 htmlhead 等外层标签 // 2. 调用转换异步返回 Promise convertHtmlToDocx(htmlContent, { orientation: portrait, // portrait | landscape margins: { top: 20, right: 15, bottom: 20, left: 15 } // 单位毫米 }) .then(blob { // 3. 创建下载链接 const url URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download 验收报告_ new Date().toISOString().slice(0,10) .docx; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); // 释放内存 }) .catch(err { console.error(DOCX 生成失败:, err); // 常见错误HTML 结构非法、图片 base64 格式错误、内存不足 });参数说明margins是唯一影响页面布局的配置项top/right/bottom/left均为数字单位严格为毫米非像素、非英寸orientation若设为landscape会自动调整页面宽高比但表格列宽需手动适配库不重排表格blob类型为application/vnd.openxmlformats-officedocument.wordprocessingml.document可直接被 Word 识别。3. 样式映射规则详解哪些 CSS 生效哪些被静默丢弃html-docx-js 不是 CSS 解析器它采用「白名单式样式提取」策略只识别预设的 HTML 标签 有限内联属性组合其余一律忽略。理解这张映射表是避免「为什么 Word 里文字变黑了」「表格没边框」等玄学问题的前提。3.1 文字样式仅支持内联 styleclass 无效HTML 写法DOCX 效果说明h1 stylecolor:red;font-size:16pt;标题/h1✅ 红色、16 磅font-size单位必须为pt磅或px1px ≈ 0.75ptem/rem无效p stylefont-family:SimSun, Microsoft YaHei;正文/p⚠️ 仅 SimSun 生效DOCX 仅保留第一个字体名且必须是系统预装字体中文推荐 SimSun、Microsoft YaHei、NSimSunspan styletext-decoration:underline;下划线/span✅ 生效line-through删除线也支持overline不支持p stylefont-weight:bold;加粗/p✅ 生效font-weight: 700同样识别但bolder/lighter无效注意strong和em标签本身会被转为加粗/斜体无需额外写style但u标签不被识别必须用text-decoration:underline。3.2 表格与列表结构优先样式次之HTML 结构DOCX 效果关键约束table border1✅ 显示边框border0或无 border 属性 → 无边框border2仍为细线DOCX 不区分 border-widthth stylebackground:#4CAF50;color:white;表头/th✅ 背景色文字色background-color仅对th和td生效且颜色值必须为#RRGGBB十六进制格式olli第一项/lili第二项/li/ol✅ 编号列表ul→ 实心圆点ol typeA→ 大写字母但start属性无效始终从 A/1 开始tabletrtd rowspan2跨行/tdtd单元格1/td/trtrtd单元格2/td/tr/table✅ 跨行生效colspan同样支持但rowspan/colspan值必须为数字字符串如2不能是变量表达式提示表格内p标签会破坏段落对齐——DOCX 中表格单元格默认居左若需居中必须给td加styletext-align:center;而非给内部p加。3.3 图片与分页base64 是唯一可行路径图片仅支持data:image/*;base64,...格式。常见翻车点img srcdata:image/png;base64,xxx→ ✅ 正确img srcdata:image/png;base64, xxx→ ❌ base64 前多空格解码失败img src/static/chart.png→ ❌ 外链禁止会报Failed to load image错误分页仅识别page-break-before: always和page-break-after: always。例如h2 stylepage-break-before:always;第二章节/h2break-inside: avoid防表格断行不支持需手动在表格前插入分页符。4. 避坑指南五个血泪经验总结的高频翻车现场4.1 现象生成的 .docx 在 Word 中提示「文件已损坏尝试修复」原因HTML 字符串中混入了不可见 Unicode 字符如\u200b零宽空格、未闭合的标签table无/table、或body外存在文本节点。html-docx-js 的 XML 构建器对 HTML 结构极其敏感任何语法瑕疵都会导致 ZIP 内部document.xml格式错误。解决在调用convertHtmlToDocx()前用 DOMParser 预校验并净化 HTMLfunction sanitizeHtml(htmlStr) { const parser new DOMParser(); const doc parser.parseFromString(htmlStr, text/html); // 移除 body 外所有内容只保留 body 内部 const body doc.body; return body ? body.innerHTML : ; } // 使用convertHtmlToDocx(sanitizeHtml(htmlContent), {...})4.2 现象中文显示为方块□□□英文正常原因DOCX 默认字体为 Calibri该字体不包含中文字符集。html-docx-js 不会自动 fallback而是静默渲染为空白。解决强制为所有段落指定中文字体。最简方案是在 HTML 最外层body加全局样式body stylefont-family: SimSun, Microsoft YaHei, sans-serif; !-- 你的内容 -- /body注意font-family必须写在body上写在p或div内无效库不继承父级字体。4.3 现象表格列宽严重失真内容挤成一团原因html-docx-js 将表格宽度解释为「绝对像素值」但 DOCX 使用「百分比 固定宽度」混合模型。当 HTML 中table width800或td width200时库会尝试转换但精度丢失严重。解决放弃width属性改用 CSSstylewidth:XX%且总和不超过 100%table stylewidth:100% tr td stylewidth:60%模块名称/td td stylewidth:40%执行状态/td /tr /table4.4 现象点击下载后文件名为download.docx而非自定义名原因Safari 浏览器尤其是 iOS对a.download属性支持不完整且当Blob创建与a.click()之间存在异步延迟时会丢失文件名。解决对 Safari 做 UA 检测改用navigator.msSaveOrOpenBlob兼容方案虽名含ms但 Safari 支持if (navigator.msSaveOrOpenBlob) { navigator.msSaveOrOpenBlob(blob, 报告.docx); } else { // 原有 Chrome/Firefox 流程 }4.5 现象大段 HTML50KB转换时卡死或内存溢出原因html-docx-js 的 XML 构建是同步字符串拼接无流式处理。当 HTML 节点数超 2000 个时V8 引擎易触发 GC 停顿。解决分块处理。将长 HTML 拆为多个section分别转换后合并需借助 docx-templates 等库或启用 Web Worker 隔离主线程// main.js const worker new Worker(/worker-converter.js); worker.postMessage({ html: longHtml }); worker.onmessage e { const blob e.data; // 触发下载 };5. 进阶技巧用自定义模板控制页眉页脚与公司 Logohtml-docx-js 原生不支持页眉页脚但可通过注入 Open XML 模板实现。其原理是先用 Word 新建一个含页眉/页脚/Logo 的空白 DOCX解压 ZIP提取word/header1.xml和word/footer1.xml再将这些 XML 片段注入到 html-docx-js 生成的 DOCX ZIP 中。这不是 hack而是 Open XML 标准的合法扩展。5.1 准备一个标准模板 DOCX.zip 解压后结构用 Word 新建文档 → 插入页眉「XX公司技术报告」→ 插入页脚「第 X 页共 Y 页」→ 插入 Logo 图片建议尺寸 120×40pxPNG 透明背景→ 另存为template.docx。将template.docx后缀改为.zip解压得到文件夹重点关注word/_rels/document.xml.rels记录外部资源关系word/header1.xml页眉内容含w:pict图片标签word/footer1.xml页脚内容word/media/image1.pngLogo 文件5.2 修改 html-docx-js 输出 ZIP注入模板文件html-docx-js 返回的Blob本质是 ZIP 文件可用 JSZip 库解包、替换、重封import JSZip from jszip; convertHtmlToDocx(htmlContent, { orientation: portrait }) .then(blob blob.arrayBuffer()) .then(buffer JSZip.loadAsync(buffer)) .then(zip { // 1. 替换 header1.xml zip.file(word/header1.xml, templateHeaderXml); // 2. 替换 footer1.xml zip.file(word/footer1.xml, templateFooterXml); // 3. 注入 Logo 图片注意路径与 rels 中一致 zip.file(word/media/image1.png, logoArrayBuffer); // 4. 更新 rels关键否则 Word 不加载页眉 const relsContent zip.file(word/_rels/document.xml.rels).asText(); const updatedRels relsContent.replace( /Relationship.*?Targetheader1.xml.*?\//, Relationship IdrId2 Typehttp://schemas.openxmlformats.org/officeDocument/2006/relationships/header Targetheader1.xml/ ); zip.file(word/_rels/document.xml.rels, updatedRels); // 5. 重新打包 return zip.generateAsync({ type: blob }); }) .then(finalBlob { // 触发下载... });关键点_rels/document.xml.rels中必须存在指向header1.xml的Relationship标签否则 Word 忽略页眉image1.png的文件名必须与header1.xml中a:blip r:embedrId1/的rId1对应需同步修改 rels。5.3 动态页码与日期用 Word 域代码Field Code页脚中的「第 X 页共 Y 页」不能靠 HTML 渲染必须用 Word 原生域代码。在footer1.xml中插入w:p w:r w:fldChar w:fldCharTypebegin/ /w:r w:r w:instrText xml:spacepreserve PAGE /w:instrText /w:r w:r w:fldChar w:fldCharTypeend/ /w:r w:rw:t / /w:t/w:r w:r w:fldChar w:fldCharTypebegin/ /w:r w:r w:instrText xml:spacepreserve NUMPAGES /w:instrText /w:r w:r w:fldChar w:fldCharTypeend/ /w:r /w:pWord 打开时会自动计算页码。同理DATE域可插入当前日期。我过去在某高校实验室做教学材料生成系统时就靠这套模板注入法把校徽、课程编号、生成时间全固化进 DOCX老师下载即用再也不用手工改页眉。后来发现真正省时间的不是代码而是把header1.xml和footer1.xml提前存成常量字符串每次只替换其中的动态字段如${courseCode}用string.replace()比 XML 解析快 10 倍。希望帮到你。本文还有配套的精品资源点击获取