html-to-word-js
Version:
一个将HTML转换为DOCX文档的TypeScript库,支持标题、段落、文本格式化、列表等常见HTML元素
847 lines (705 loc) • 22.7 kB
Markdown
# 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
<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
<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
<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)