
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
html-to-word-js
Advanced tools
一个功能强大的 HTML 到 Word 文档转换器,专为浏览器环境设计,支持丰富的样式和格式,能够将 HTML 内容准确转换为 DOCX 格式的 Word 文档。
# 使用 npm
npm install html-to-word-js
# 使用 yarn
yarn add html-to-word-js
# 使用 pnpm
pnpm add html-to-word-js
注意:此库专为浏览器环境设计,不支持 Node.js 环境。
// 浏览器环境使用
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)
<!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>
<!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>
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 类型,可直接用于下载
| 标签 | 说明 | 样式支持 |
|---|---|---|
<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"> | 复选框 | 选中状态、样式 |
<p style="color: #FF0000;">红色文字</p>
<p style="color: rgb(0, 255, 0);">绿色文字</p>
<p style="background-color: #FFFF00;">黄色背景</p>
<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>
<p style="text-align: center;">居中对齐</p>
<p style="text-indent: 2em;">首行缩进</p>
<p style="margin-left: 20px;">左边距</p>
<p style="line-height: 1.5;">1.5倍行距</p>
<p style="line-height: 24pt;">固定行距24磅</p>
<p style="border: 1px solid red;">红色边框</p>
<p style="border: 2px dashed blue;">蓝色虚线边框</p>
<!-- 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;" />
<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>
<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>
<a href="https://example.com" style="color: blue; text-decoration: underline;">
点击访问网站
</a>
<!-- 基本分割线 -->
<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">
<!-- 基本复选框 -->
<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;" />
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'
}
}
};
页眉页脚支持样式优先级处理,确保灵活性和精确控制:
<!-- 这个段落会保持右对齐,忽略配置中的对齐设置 -->
<p style="text-align: right;">右对齐的页眉</p>
<!-- 这个段落会使用配置中的对齐设置 -->
<p>使用配置对齐的页眉</p>
const options = {
header: {
content: `
<p style="text-align: center;">居中对齐(HTML样式优先)</p>
<p>左对齐(使用配置样式)</p>
<h3>标题(使用配置样式)</h3>
`,
style: {
alignment: 'left' // 只应用到没有text-align的元素
}
}
};
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 样式,可以创建中划线文字:
<!-- 基本中划线 -->
<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:
<!-- 使用 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: leftdata-scale="120" 等同于 transform: scaleX(1.2); transform-origin: leftcreator - 创建者title - 文档标题subject - 文档主题description - 文档描述keywords - 关键词 (用逗号分隔)revision - 修订版本 (数字)lastModifiedBy - 最后修改者const options = {
properties: {
creator: '张三',
title: '项目报告',
subject: '季度总结',
description: '2024年第一季度项目进展报告',
keywords: '项目,报告,总结',
revision: 1,
lastModifiedBy: '张三'
}
};
注意:此库专为浏览器环境设计,不支持在 Node.js 中运行。
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'; // 文本对齐方式
};
};
}
function convertHtmlToDocxBuffer(
html: string,
options?: HtmlToWordOptions
): Promise<{
buffer: Uint8Array; // 浏览器环境返回 Uint8Array
warnings: string[];
}>
function htmlToDocx(
html: string,
options?: HtmlToDocxOptions
): Promise<{
document: Document;
warnings: string[];
}>
function docxToBuffer(
document: Document
): Promise<Uint8Array> // 浏览器环境返回 Uint8Array
<!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>
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;
<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
FAQs
一个将HTML转换为DOCX文档的TypeScript库,支持标题、段落、文本格式化、列表等常见HTML元素
We found that html-to-word-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.