UNPKG

html-to-word-js

Version:

一个将HTML转换为DOCX文档的TypeScript库,支持标题、段落、文本格式化、列表等常见HTML元素

847 lines (705 loc) 22.7 kB
# HTML to Word 一个功能强大的 HTML 到 Word 文档转换器,专为浏览器环境设计,支持丰富的样式和格式,能够将 HTML 内容准确转换为 DOCX 格式的 Word 文档。 ## ✨ 主要特性 - 🌐 **浏览器专用** - 专为浏览器环境设计,不支持 Node.js - 📦 **多格式支持** - 支持 IIFE、UMD 和 ES 模块格式 - 🎨 **完整的样式支持** - 支持颜色、字体、大小、对齐、缩进等所有常用样式 - 📄 **文档属性设置** - 支持设置创建者、标题、主题、关键词等文档元数据 - 🖼️ **图片处理** - 支持 base64、blob URL 和远程图片 - 📊 **表格支持** - 完整的表格样式和格式化 - 🔗 **超链接** - 支持可点击的超链接 - 📏 **分割线** - 支持 HR 标签生成水平分割线 - ☑️ **复选框** - 支持 checkbox 标签生成复选框 - 📄 **页眉页脚** - 支持自定义页眉页脚内容和样式 - 📝 **字符间距** - 支持字符间距缩放功能 - 🎯 **精确转换** - 保持原始 HTML 的样式和格式 ## 🚀 快速开始 ### 安装 #### 从 NPM 安装 ```bash # 使用 npm npm install html-to-word-js # 使用 yarn yarn add html-to-word-js # 使用 pnpm pnpm add html-to-word-js ``` **注意:此库专为浏览器环境设计,不支持 Node.js 环境。** ## 📖 使用方法 ### 基本用法 #### ES 模块方式(推荐) ```typescript // 浏览器环境使用 import { convertHtmlToDocxBuffer } from 'html-to-word-js'; const html = ` <h1 style="color: #2E86C1; font-size: 24pt;">文档标题</h1> <p style="color: #34495E; font-size: 14pt;">这是一个段落。</p> `; const result = await convertHtmlToDocxBuffer(html); // result.buffer 包含 DOCX 文件数据 (Uint8Array) ``` #### IIFE 方式(浏览器直接使用) ```html <!DOCTYPE html> <html> <head> <title>HTML to Word 示例</title> <script src="https://unpkg.com/html-to-word-js@latest/dist/browser/index.js"></script> </head> <body> <button onclick="convertToWord()">转换为 Word</button> <script> async function convertToWord() { const html = ` <h1 style="color: #2E86C1;">文档标题</h1> <p style="color: #34495E;">这是一个段落。</p> `; try { const result = await window.HtmlToWordConverter.convertHtmlToDocxBuffer(html); // 创建下载链接 const blob = new Blob([result.buffer], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'document.docx'; a.click(); window.URL.revokeObjectURL(url); } catch (error) { console.error('转换失败:', error); } } </script> </body> </html> ``` #### UMD 方式 ```html <!DOCTYPE html> <html> <head> <title>HTML to Word 示例</title> <script src="https://unpkg.com/html-to-word-js@latest/dist/umd/index.umd.js"></script> </head> <body> <button onclick="convertToWord()">转换为 Word</button> <script> async function convertToWord() { const html = ` <h1 style="color: #2E86C1;">文档标题</h1> <p style="color: #34495E;">这是一个段落。</p> `; try { const result = await HtmlToWordConverter.convertHtmlToDocxBuffer(html); // 创建下载链接 const blob = new Blob([result.buffer], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'document.docx'; a.click(); window.URL.revokeObjectURL(url); } catch (error) { console.error('转换失败:', error); } } </script> </body> </html> ``` ### 高级用法 ```typescript import { convertHtmlToDocxBuffer } from 'html-to-word-js'; const html = ` <h1>我的文档</h1> <p>这是文档内容。</p> `; const options = { // 页面设置 margins: { top: 2.54, // 上边距 (厘米) right: 2.54, // 右边距 (厘米) bottom: 2.54, // 下边距 (厘米) left: 2.54 // 左边距 (厘米) }, // 图片设置 maxImageWidth: 600, // 图片最大宽度 (像素) maxImageHeight: 400, // 图片最大高度 (像素) // 文档属性 properties: { creator: '张三', title: '我的文档标题', subject: '文档主题', description: '文档描述', keywords: '关键词1,关键词2', revision: 1, lastModifiedBy: '张三' } }; const result = await convertHtmlToDocxBuffer(html, options); // result.buffer 是 Uint8Array 类型,可直接用于下载 ``` ## 🎨 支持的 HTML 标签和样式 ### 基础标签 | 标签 | 说明 | 样式支持 | |------|------|----------| | `<h1>` - `<h6>` | 标题 | 颜色、字体、大小、缩进 | | `<p>`, `<div>` | 段落 | 颜色、字体、大小、缩进、对齐 | | `<strong>`, `<b>` | 粗体 | 颜色、字体、大小 | | `<em>`, `<i>` | 斜体 | 颜色、字体、大小 | | `<u>` | 下划线 | 颜色、字体、大小 | | `<span style="text-decoration: line-through">` | 中划线 | 颜色、字体、大小 | | `<a>` | 超链接 | 颜色、字体、大小 | | `<ul>`, `<ol>`, `<li>` | 列表 | 颜色、字体、大小、缩进 | | `<small>`, `<big>` | 字体大小 | 自动调整 | | `<sub>`, `<sup>` | 上下标 | 自动调整 | | `<img>` | 图片 | 尺寸、缩进 | | `<table>`, `<tr>`, `<td>`, `<th>` | 表格 | 完整样式支持,合并单元格 | | `<br>` | 换行 | - | | `<hr>` | 分割线 | 边框样式 | | `<input type="checkbox">` | 复选框 | 选中状态、样式 | ### 样式属性 #### 颜色和背景 ```html <p style="color: #FF0000;">红色文字</p> <p style="color: rgb(0, 255, 0);">绿色文字</p> <p style="background-color: #FFFF00;">黄色背景</p> ``` #### 字体样式 ```html <p style="font-family: 'Arial'; font-size: 16pt; font-weight: bold;"> 粗体 Arial 字体,16pt 大小 </p> #### 文本装饰 ```html <p style="text-decoration: underline;">下划线文字</p> <p style="text-decoration: line-through;">中划线文字</p> <p style="text-decoration: underline line-through;">下划线+中划线文字</p> ``` #### 对齐和缩进 ```html <p style="text-align: center;">居中对齐</p> <p style="text-indent: 2em;">首行缩进</p> <p style="margin-left: 20px;">左边距</p> ``` #### 行高 ```html <p style="line-height: 1.5;">1.5倍行距</p> <p style="line-height: 24pt;">固定行距24磅</p> ``` #### 边框 ```html <p style="border: 1px solid red;">红色边框</p> <p style="border: 2px dashed blue;">蓝色虚线边框</p> ``` ## 🖼️ 图片支持 ### 支持的格式 - **Base64 图片** - 完全支持 - **Blob URL** - 完全支持 - **远程图片** - 完全支持 ### 使用示例 ```html <!-- Base64 图片 --> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAE/ycPkJQAAAABJRU5ErkJggg==" alt="图片" /> <!-- 远程图片 --> <img src="https://example.com/image.jpg" alt="远程图片" /> <!-- Blob URL 图片 --> <img src="blob:http://localhost:3000/abc123" alt="Blob图片" /> <!-- 带样式的图片 --> <img src="data:image/png;base64,..." style="width: 300px; margin-left: 20px;" /> ``` ## 📊 表格支持 ### 基本表格 ```html <table style="border: 1px solid #333;"> <thead> <tr> <th style="color: blue; text-align: center;">产品</th> <th style="color: red; text-align: center;">价格</th> </tr> </thead> <tbody> <tr> <td>笔记本</td> <td style="text-align: right;">¥8,999</td> </tr> </tbody> </table> ``` ### 合并单元格表格 ```html <table border="1" style="width: 100%;"> <thead> <tr> <th colspan="3" style="text-align: center; background-color: #4CAF50; color: white;">销售报表</th> </tr> <tr> <th>产品</th> <th>数量</th> <th>金额</th> </tr> </thead> <tbody> <tr> <td rowspan="2" style="background-color: #f9f9f9;">笔记本电脑</td> <td>10</td> <td>¥89,990</td> </tr> <tr> <td>5</td> <td>¥44,995</td> </tr> </tbody> <tfoot> <tr> <td colspan="2" style="text-align: right; font-weight: bold;">总计:</td> <td style="font-weight: bold;">¥134,985</td> </tr> </tfoot> </table> ``` ### 表格样式 - 支持背景色、边框样式 - 支持单元格格式化 - 支持表头和表体 - 支持合并单元格(colspan、rowspan) - 自动添加表格边框 ## 🔗 超链接 ```html <a href="https://example.com" style="color: blue; text-decoration: underline;"> 点击访问网站 </a> ``` ## 📏 分割线 (HR 标签) ```html <!-- 基本分割线 --> <hr> <!-- 带样式的分割线 --> <hr style="border: 2px solid red; margin: 20px 0;"> <!-- 带CSS类的分割线 --> <style> .custom-hr { border: 3px dashed blue; margin: 30px 0; } </style> <hr class="custom-hr"> ``` ## ☑️ 复选框 (Checkbox) ```html <!-- 基本复选框 --> <input type="checkbox" label="未选中的选项" /> <input type="checkbox" checked label="已选中的选项" /> <!-- 带样式的复选框 --> <input type="checkbox" checked label="重要选项" style="color: red; font-weight: bold;" /> <!-- 问卷调查示例 --> <p>请选择您喜欢的编程语言:</p> <input type="checkbox" label="JavaScript" /> <input type="checkbox" checked label="TypeScript" /> <input type="checkbox" label="Python" /> <!-- 用户协议 --> <input type="checkbox" checked label="我已阅读并同意用户协议" style="color: #E74C3C; font-weight: bold;" /> ``` ## 📄 页眉页脚 (Header & Footer) ```typescript const options = { header: { content: '<h3 style="color: #2E86C1;">公司名称</h3><p>文档标题</p>', style: { fontSize: 16, fontFamily: 'Arial', color: '2E86C1', alignment: 'center' } }, footer: { content: '<p style="text-align: center;"><strong>1</strong></p>', style: { fontSize: 14, fontFamily: 'Arial', color: '666666', alignment: 'center' } } }; ``` ### 页眉页脚功能特点 - **HTML内容支持**: 支持完整的HTML格式,包括段落、标题、样式等 - **样式自定义**: 支持字体大小、字体名称、颜色、对齐方式等 - **文本样式**: 支持粗体、斜体、下划线等文本样式 - **标签支持**: 支持 p、div、span、h1-h6、strong、em、u 等标签 - **样式优先级**: HTML内联样式优先于配置中的样式设置 - **应用场景**: 公司文档、报告、合同等需要统一页眉页脚的文档 ### 样式优先级说明 页眉页脚支持样式优先级处理,确保灵活性和精确控制: #### 1. HTML内联样式优先 ```html <!-- 这个段落会保持右对齐,忽略配置中的对齐设置 --> <p style="text-align: right;">右对齐的页眉</p> <!-- 这个段落会使用配置中的对齐设置 --> <p>使用配置对齐的页眉</p> ``` #### 2. 配置样式补充 ```typescript const options = { header: { content: ` <p style="text-align: center;">居中对齐(HTML样式优先)</p> <p>左对齐(使用配置样式)</p> <h3>标题(使用配置样式)</h3> `, style: { alignment: 'left' // 只应用到没有text-align的元素 } } }; ``` #### 3. 混合使用示例 ```typescript const options = { header: { content: ` <h3 style="text-align: center;">公司名称(居中)</h3> <p>文档标题(使用配置对齐)</p> <p style="text-align: right;">日期:2024-01-01(右对齐)</p> `, style: { fontSize: 16, alignment: 'left' // 只应用到没有text-align的元素 } } }; ``` ## 📝 中划线功能 支持 `text-decoration: line-through` 样式,可以创建中划线文字: ```html <!-- 基本中划线 --> <p style="text-decoration: line-through;">中划线文字</p> <!-- 带颜色的中划线 --> <p style="text-decoration: line-through; color: red;">红色中划线文字</p> <!-- 组合样式 --> <p style="text-decoration: line-through; font-weight: bold; color: blue;">蓝色粗体中划线</p> <!-- 部分文字中划线 --> <p>正常文字 <span style="text-decoration: line-through;">中划线部分</span> 正常文字</p> <!-- 下划线+中划线组合 --> <p style="text-decoration: underline line-through;">下划线+中划线文字</p> ``` ### 中划线功能特点 - ✅ 支持完整段落中划线 - ✅ 支持部分文字中划线 - ✅ 支持与其他样式组合(粗体、斜体、颜色等) - ✅ 支持与下划线同时使用 - ✅ 支持在表格、列表等元素中使用 ## 📝 字符间距缩放 使用 `data-scale` 属性调整字符间距,等同于 CSS 样式 `transform: scaleX` 和 `transform-origin: left`: ```html <!-- 使用 data-scale 属性 --> <p> 正常间距文字 <span data-scale="55" style="color: red;">55%间距缩放</span> <span data-scale="120" style="color: blue;">120%间距缩放</span> </p> <!-- 等价的 CSS 样式 --> <p> 正常间距文字 <span style="transform: scaleX(0.55); transform-origin: left; color: red;">55%间距缩放</span> <span style="transform: scaleX(1.2); transform-origin: left; color: blue;">120%间距缩放</span> </p> ``` ### 字符间距缩放特点 - ✅ `data-scale="55"` 等同于 `transform: scaleX(0.55); transform-origin: left` - ✅ `data-scale="120"` 等同于 `transform: scaleX(1.2); transform-origin: left` - ✅ 保持字体大小不变,仅调整字符之间的间距 - ✅ 支持任意正数百分比值 - ✅ 可以与所有其他样式组合使用 - ✅ 在 DOCX 中转换为字符间距缩放效果 ## 📄 文档属性设置 ### 支持的属性 - `creator` - 创建者 - `title` - 文档标题 - `subject` - 文档主题 - `description` - 文档描述 - `keywords` - 关键词 (用逗号分隔) - `revision` - 修订版本 (数字) - `lastModifiedBy` - 最后修改者 ### 使用示例 ```typescript const options = { properties: { creator: '张三', title: '项目报告', subject: '季度总结', description: '2024年第一季度项目进展报告', keywords: '项目,报告,总结', revision: 1, lastModifiedBy: '张三' } }; ``` ## 🌐 环境支持 ### 浏览器环境 ✅ - ✅ 支持所有图片格式 (base64, blob URL, 远程图片) - ✅ 支持所有样式功能 - ✅ 支持实时转换 - ✅ 支持完整的 HTML 到 DOCX 转换功能 ### Node.js 环境 ❌ - ❌ **不支持 Node.js 环境** - ❌ 无法处理 blob URL 和远程图片 - ❌ 缺少浏览器特定的 API 支持 **注意:此库专为浏览器环境设计,不支持在 Node.js 中运行。** ## 🔧 配置选项 ### HtmlToWordOptions 接口 ```typescript interface HtmlToWordOptions { // 页面方向 orientation?: 'portrait' | 'landscape'; // 页边距 (厘米) margins?: { top?: number; right?: number; bottom?: number; left?: number; }; // 图片最大尺寸 (像素) maxImageWidth?: number; maxImageHeight?: number; // 文档属性 properties?: { creator?: string; description?: string; title?: string; subject?: string; keywords?: string; revision?: number; lastModifiedBy?: string; }; // 页眉设置 header?: { content?: string; // 页眉内容 (HTML字符串) style?: { fontSize?: number; // 字体大小 (半点) fontFamily?: string; // 字体名称 color?: string; // 字体颜色 (hex) bold?: boolean; // 是否粗体 italic?: boolean; // 是否斜体 alignment?: 'left' | 'center' | 'right'; // 文本对齐方式 }; }; // 页脚设置 footer?: { content?: string; // 页脚内容 (HTML字符串) style?: { fontSize?: number; // 字体大小 (半点) fontFamily?: string; // 字体名称 color?: string; // 字体颜色 (hex) bold?: boolean; // 是否粗体 italic?: boolean; // 是否斜体 alignment?: 'left' | 'center' | 'right'; // 文本对齐方式 }; }; } ``` ## 📦 API 参考 ### convertHtmlToDocxBuffer ```typescript function convertHtmlToDocxBuffer( html: string, options?: HtmlToWordOptions ): Promise<{ buffer: Uint8Array; // 浏览器环境返回 Uint8Array warnings: string[]; }> ``` ### htmlToDocx ```typescript function htmlToDocx( html: string, options?: HtmlToDocxOptions ): Promise<{ document: Document; warnings: string[]; }> ``` ### docxToBuffer ```typescript function docxToBuffer( document: Document ): Promise<Uint8Array> // 浏览器环境返回 Uint8Array ``` ## 📝 注意事项 1. **环境要求**: 此库仅支持浏览器环境,不支持 Node.js 2. **图片处理**: 支持 base64、blob URL 和远程图片格式 3. **样式继承**: 支持 CSS 样式继承和优先级 4. **错误处理**: 转换过程中会收集警告信息 5. **性能**: 大文档转换可能需要较长时间 6. **兼容性**: 生成的 DOCX 文件兼容 Microsoft Word、WPS 等 7. **CDN 使用**: 可以通过 unpkg 或 jsDelivr 等 CDN 直接使用 ## 🚀 快速开始示例 ### 最简单的使用方式 ```html <!DOCTYPE html> <html> <head> <title>HTML to Word 快速开始</title> <script src="https://unpkg.com/html-to-word-js@latest/dist/browser/index.js"></script> </head> <body> <h1>HTML to Word 转换器</h1> <textarea id="htmlInput" rows="10" cols="50"> <h1 style="color: #2E86C1;">我的文档</h1> <p style="color: #34495E;">这是一个段落。</p> <ul> <li>列表项 1</li> <li>列表项 2</li> </ul> </textarea> <br> <button onclick="convert()">转换为 Word 文档</button> <script> async function convert() { const html = document.getElementById('htmlInput').value; try { const result = await window.HtmlToWordConverter.convertHtmlToDocxBuffer(html); // 下载文件 const blob = new Blob([result.buffer], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = '我的文档.docx'; a.click(); window.URL.revokeObjectURL(url); console.log('转换成功!'); if (result.warnings.length > 0) { console.log('警告信息:', result.warnings); } } catch (error) { console.error('转换失败:', error); } } </script> </body> </html> ``` ### 在 React 项目中使用 ```tsx import React, { useState } from 'react'; import { convertHtmlToDocxBuffer } from 'html-to-word-js'; function WordConverter() { const [html, setHtml] = useState(''); const [loading, setLoading] = useState(false); const handleConvert = async () => { if (!html.trim()) { alert('请输入HTML内容'); return; } setLoading(true); try { const result = await convertHtmlToDocxBuffer(html); // 下载文件 const blob = new Blob([result.buffer], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = '文档.docx'; a.click(); window.URL.revokeObjectURL(url); if (result.warnings.length > 0) { console.log('警告信息:', result.warnings); } } catch (error) { console.error('转换失败:', error); alert('转换失败,请检查控制台'); } finally { setLoading(false); } }; return ( <div> <textarea value={html} onChange={(e) => setHtml(e.target.value)} placeholder="请输入HTML内容..." rows={10} cols={50} /> <br /> <button onClick={handleConvert} disabled={loading}> {loading ? '转换中...' : '转换为Word'} </button> </div> ); } export default WordConverter; ``` ### 在 Vue 项目中使用 ```vue <template> <div> <textarea v-model="html" placeholder="请输入HTML内容..." rows="10" cols="50" ></textarea> <br /> <button @click="convertToWord" :disabled="loading"> {{ loading ? '转换中...' : '转换为Word' }} </button> </div> </template> <script> import { convertHtmlToDocxBuffer } from 'html-to-word-js'; export default { data() { return { html: '', loading: false }; }, methods: { async convertToWord() { if (!this.html.trim()) { alert('请输入HTML内容'); return; } this.loading = true; try { const result = await convertHtmlToDocxBuffer(this.html); // 下载文件 const blob = new Blob([result.buffer], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = '文档.docx'; a.click(); window.URL.revokeObjectURL(url); if (result.warnings.length > 0) { console.log('警告信息:', result.warnings); } } catch (error) { console.error('转换失败:', error); alert('转换失败,请检查控制台'); } finally { this.loading = false; } } } }; </script> ``` ## 🤝 贡献 欢迎提交 Issue 和 Pull Request! ## 📄 许可证 MIT License ## 🔗 相关链接 - [docx 库文档](https://docx.js.org/) - [Word 文档格式规范](https://docs.microsoft.com/en-us/office/open-xml/open-xml-sdk)