Word 文档长期承担说明书、报告与合同的编写工作;Markdown 则以纯文本形式服务于文档站点、知识库与代码仓库。把已有的 Word 内容转入 Markdown,是文档迁移与内容发布中的常见环节。
若把转换放在服务端,文件需要先上传,原始内容因此离开用户的设备。本文使用 Spire.Doc for JavaScript 在浏览器中完成转换:Word 文档通过虚拟文件系统(VFS)读入,导出结果同样写回 VFS,再由页面读取并触发下载。整个过程基于 WebAssembly 在浏览器端运行,无需安装 Office,也不依赖后端服务。
本文介绍三个功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例假定 Spire.Doc 已安装、WebAssembly 模块已初始化。
将 Word 文档转换为 Markdown
转换由 Document.LoadFromFile() 与 Document.SaveToFile() 两步完成:前者把 .docx 读入文档对象,后者以 FileFormat.Markdown 为目标格式写出 .md 文件。保存结果先落在 VFS 中,再由页面读取并下载。
文档结构按对应语法写入 Markdown,主要映射关系如下:
| Word 内容 | Markdown 输出 |
|---|---|
| 应用 Heading 1、Heading 2 等内置标题样式的段落 | 对应级别的 #、## 标题 |
| 加粗、斜体 | **文本**、*文本* |
| 项目符号列表 | - 条目 |
| 编号列表 | 1. 条目 |
| 表格 | 管道表格,表头文字加粗 |
| 图片 | ,图片单独写出 |
| 超链接 | [文字](地址) |
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 将示例文档
产品发布说明.docx载入虚拟文件系统(VFS)。 - 创建
Document对象并加载该文档。 - 将
MarkdownExportOptions.ImagesFolder设为images,图片写入该目录。 - 使用
SaveToFile()以FileFormat.Markdown保存,生成产品发布说明.md。 - 从 VFS 读出 Markdown 文本与图片文件,分别触发浏览器下载。
将 Word 文档转换为 Markdown 的代码如下:
// 从 VFS 读出文件并触发下载
function downloadBlob(blob, fileName) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
}
function App() {
const convertToMarkdown = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 确保 WASM 模块完全加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文档载入虚拟文件系统
await window.spire.FetchFileToVFS('产品发布说明.docx', '', `${process.env.PUBLIC_URL}/data/`);
// 创建 Document 实例并加载 Word 文档
const doc = new docModule.Document();
doc.LoadFromFile('产品发布说明.docx', docModule.FileFormat.Docx2016);
// 图片写入 VFS 的 images 目录,Markdown 中以相对路径引用
doc.MarkdownExportOptions.ImagesFolder = 'images';
// 以 Markdown 格式保存,结果写入 VFS
const outputFileName = '产品发布说明.md';
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Markdown });
doc.Dispose();
const FS = window.dotnetRuntime.Module.FS;
// 读取 Markdown 文本并下载(UTF-8 编码)
const text = new TextDecoder('utf-8').decode(FS.readFile(outputFileName));
downloadBlob(new Blob([text], { type: 'text/markdown;charset=utf-8' }), outputFileName);
// 图片单独存放,需要一并下载
FS.readdir('images')
.filter((name) => name !== '.' && name !== '..')
.forEach((name) => {
const data = FS.readFile(`images/${name}`);
downloadBlob(new Blob([data], { type: 'image/png' }), name);
});
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>将 Word 转换为 Markdown</h1>
<button onClick={convertToMarkdown}>
转换并下载
</button>
</div>
);
}
export default App;
转换生成的 Markdown 在浏览器中渲染后,标题、列表、表格、超链接与图片均按对应的语法呈现:

将图片保存到指定目录
未设置 ImagesFolder 时,图片写入 VFS 的根目录,文件名以输出文件名为前缀,例如 产品发布说明_001.png,Markdown 中的引用为 /产品发布说明_001.png。这种写法便于直接定位文件,但引用带有根目录前缀。将 ImagesFolder 设为相对目录后,图片写入 VFS 的该目录,引用也变为相对路径:
doc.MarkdownExportOptions.ImagesFolder = 'images';
转换结果中相应出现 images/产品发布说明_001.png 这样的引用。图片需要与 .md 一并下载,页面可通过 FS.readdir() 列出目录内容后逐个读取并下载,写法见上一段示例;若希望结果只有一个文件,可改用下一节的 Base64 方式。
将图片内嵌为 Base64
设置 MarkdownExportOptions.ImagesAsBase64 = true 后,文档中的图片不再单独写出,而是编码为 data URI 直接写进 ![]() 的括号内。转换结果是单个 .md 文件,复制、上传或提交到仓库时不会出现图片路径失效的问题。
代价是文件体积增大:Base64 编码后的数据约为原图的 4/3。图片较多或分辨率较高时,单个 Markdown 文件的体积会明显上升。
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 将示例文档
产品发布说明.docx载入虚拟文件系统(VFS)。 - 创建
Document对象并加载该文档。 - 将
MarkdownExportOptions.ImagesAsBase64设为true。 - 使用
SaveToFile()以FileFormat.Markdown保存,并从 VFS 读出文本触发下载。
将图片内嵌为 Base64 的代码如下:
function downloadBlob(blob, fileName) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
}
function App() {
const convertWithBase64 = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 确保 WASM 模块完全加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文档载入虚拟文件系统
await window.spire.FetchFileToVFS('产品发布说明.docx', '', `${process.env.PUBLIC_URL}/data/`);
// 创建 Document 实例并加载 Word 文档
const doc = new docModule.Document();
doc.LoadFromFile('产品发布说明.docx', docModule.FileFormat.Docx2016);
// 图片以内嵌 Base64 的方式写入 Markdown
doc.MarkdownExportOptions.ImagesAsBase64 = true;
// 保存结果文件
const outputFileName = '产品发布说明-内嵌图片.md';
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Markdown });
doc.Dispose();
// 读取 Markdown 文本并下载,无需再单独下载图片
const text = new TextDecoder('utf-8').decode(window.dotnetRuntime.Module.FS.readFile(outputFileName));
downloadBlob(new Blob([text], { type: 'text/markdown;charset=utf-8' }), outputFileName);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>将图片内嵌为 Base64</h1>
<button onClick={convertWithBase64}>
转换并下载
</button>
</div>
);
}
export default App;
内嵌之后,图片以 data:image/png;base64, 开头的一长串字符出现在 Markdown 中,文件本身不再伴随图片文件:

自定义 Markdown 导出选项
Document.MarkdownExportOptions 集中控制 Markdown 的写法。除图片处理外,列表、链接、表格、下划线与公式都可以单独调整:
| 选项 | 常用取值 | 作用 |
|---|---|---|
ImagesFolder |
目录名 | 图片写入 VFS 的指定目录,Markdown 用该目录引用 |
ImagesAsBase64 |
true / false |
图片以 data URI 内嵌 |
ListOutputMode |
MarkdownSyntax / PlainText |
输出列表语法,或把列表符号转义为普通文本 |
LinkOutputMode |
Auto / Inline / Reference |
行内链接,或引用式链接 |
SaveAsHtml |
None / Tables |
表格保留管道语法,或以 HTML 表格输出 |
SaveUnderlineFormatting |
true / false |
下划线是否保留为 ++文本++ |
OfficeMathOutputMode |
Text / Image / MathML |
公式的输出去向 |
其中 SaveAsHtml 设为 Tables 时,导出过程需要字体参与表格排版;未载入字体时保存会抛出 Cannot find any fonts in specified font sources.。示例因此先把字体载入 VFS,再执行转换。只导出文字、列表与图片时不需要这一步。
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 将字体
msyh.ttc、msyhbd.ttc与示例文档载入虚拟文件系统(VFS)。 - 创建
Document对象并加载 Word 文档。 - 取得
MarkdownExportOptions,依次设置图片目录、列表、链接、表格与下划线选项。 - 使用
SaveToFile()以FileFormat.Markdown保存结果文件。 - 从 VFS 读出 Markdown 文本与图片文件,分别触发浏览器下载。
自定义 Markdown 导出选项的代码如下:
function downloadBlob(blob, fileName) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
}
function App() {
const convertWithOptions = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 确保 WASM 模块完全加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 导出 HTML 表格时需要字体参与排版,先将字体载入 VFS
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
await window.spire.FetchFileToVFS('msyhbd.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 将示例文档载入虚拟文件系统
await window.spire.FetchFileToVFS('产品发布说明.docx', '', `${process.env.PUBLIC_URL}/data/`);
// 创建 Document 实例并加载 Word 文档
const doc = new docModule.Document();
doc.LoadFromFile('产品发布说明.docx', docModule.FileFormat.Docx2016);
// 自定义 Markdown 导出选项
const options = doc.MarkdownExportOptions;
options.ImagesFolder = 'images';
options.ListOutputMode = docModule.MarkdownListOutputMode.PlainText;
options.LinkOutputMode = docModule.MarkdownLinkOutputMode.Reference;
options.SaveAsHtml = docModule.MarkdownSaveAsHtml.Tables;
options.SaveUnderlineFormatting = true;
// 保存结果文件
const outputFileName = '产品发布说明-导出选项.md';
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Markdown });
doc.Dispose();
const FS = window.dotnetRuntime.Module.FS;
// 下载 Markdown 文本
const text = new TextDecoder('utf-8').decode(FS.readFile(outputFileName));
downloadBlob(new Blob([text], { type: 'text/markdown;charset=utf-8' }), outputFileName);
// 下载写出的图片
FS.readdir('images')
.filter((name) => name !== '.' && name !== '..')
.forEach((name) => downloadBlob(new Blob([FS.readFile(`images/${name}`)], { type: 'image/png' }), name));
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>自定义 Markdown 导出选项</h1>
<button onClick={convertWithOptions}>
转换并下载
</button>
</div>
);
}
export default App;
以上选项生效后,输出中的列表、链接、表格与下划线分别换了写法,部分输出如下:
\- 单份文档的生成时间由 6 分钟缩短至 10 秒以内。
\- 合同与薪酬类文件不再经过服务端中转。
\- 导出页数与屏幕预览保持一致。
\1. 替换前端工程中的 WebAssembly 资源包。
\2. 清理浏览器缓存并重新加载页面。
\3. 使用示例文档核对转换结果。
前端项目通过 WebAssembly 模块调用文档接口,完整的接口说明见 [在线文档平台接口文档] ,示例工程已随版本发布。
升级前请先阅读 ++兼容性说明++ ,并确认现有文档的样式不受影响。
[在线文档平台接口文档]: https://www.e-iceblue.com/
[ref1]: images/产品发布说明-导出选项_001.png
设置列表与链接的输出方式
ListOutputMode 默认为 MarkdownSyntax,项目符号与编号分别写成 - 与 1.;改为 PlainText 后,符号前会加上反斜杠转义,即 \-、\1.,渲染时呈现为普通文本,不再构成列表。
LinkOutputMode 默认为 Auto,超链接写成行内形式 [文字](地址);改为 Reference 后,正文中只保留 [文字],实际地址集中写在文末的链接定义处,图片同样改用 ![ref1] 加定义行的写法。链接较多、且地址需要统一维护时,引用式写法更便于阅读。
const options = doc.MarkdownExportOptions;
options.ListOutputMode = docModule.MarkdownListOutputMode.PlainText;
options.LinkOutputMode = docModule.MarkdownLinkOutputMode.Reference;
将表格保存为 HTML
SaveAsHtml 默认为 None,表格按管道语法输出,表头文字加粗;改为 Tables 后,表格以 <table> 标签输出,单元格样式写在行内,列宽、边框与文字格式随之保留。输出是一整行 HTML,不再受管道语法的限制。
需要注意两点:其一,该选项要求字体已载入 VFS,否则保存时报错;其二,表格之后若紧跟标题,部分 Markdown 解析器会把标题行并入表格,在 Word 中为表格后留一个空段落即可避免。
options.SaveAsHtml = docModule.MarkdownSaveAsHtml.Tables;
保留下划线格式
Markdown 没有标准的下划线语法,默认导出会丢弃 Word 中的下划线。设置 SaveUnderlineFormatting = true 后,下划线文字写成 ++文本++。该写法属于扩展语法,目标平台是否将其渲染为下划线,取决于所用解析器的支持情况。
options.SaveUnderlineFormatting = true;

常见问题
转换后的 Markdown 里为什么找不到图片文件
原因:图片默认与 .md 分开写出,文件位于 VFS 的根目录,名称以输出文件名为前缀。页面上只读取并下载了 .md 时,图片自然不会出现在下载结果中。
解决:设置 ImagesFolder 指定图片目录,转换后连同该目录中的图片一并下载;也可以设置 ImagesAsBase64 = true,让图片直接写入 Markdown,结果只保留一个文件。
为什么 Word 中的下划线在 Markdown 中消失了
原因:Markdown 没有标准的下划线语法,SaveUnderlineFormatting 默认为 false,导出时会丢弃下划线格式。
解决:设置 SaveUnderlineFormatting = true,下划线文字会写成 ++文本++。该语法并非所有 Markdown 解析器都支持,使用前宜确认目标平台的渲染情况。
为什么标题没有转换成 # 标题
原因:导出时按标题样式识别标题,只有应用了 Heading 1、Heading 2 等内置标题样式的段落才会转换为对应级别的 # 标题。仅把文字加粗、放大字号,或套用 Title 样式的段落,输出仍是普通段落。
解决:为需要成为标题的段落应用内置标题样式;原本使用 Title 样式的文档标题,可改为 Heading 1,或转换后在 Markdown 中手动补上 #。
表格后面的标题被并入表格怎么办
原因:表格与后续标题之间没有空行时,部分 Markdown 解析器会把紧邻的标题行当作表格的一行。
解决:在 Word 中为表格后留一个空段落再写标题,导出的 Markdown 中会出现空行;也可以在转换后于表格与标题之间补一个空行。
转换过程需要把文件上传到服务器吗
本文的用法不需要上传。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端运行,Word 文档与转换结果都通过虚拟文件系统(VFS)在本地读写,库本身不会把文件发往服务器。文件最终是否会离开设备,取决于页面上另外接入的代码。
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







