在日常工作中,大部分人都会应用 Microsoft Office Word、WPS 或 macOS Pages 等文字处理程序进行 Word 文档解决。除了应用上述的文字处理程序之外,对于 Word 文档来说,还有其余的解决形式么?答案是有的。
接下来阿宝哥将介绍在前端如何玩转 Word 文档,浏览本文之后,你将理解以下内容:
- Microsoft Office Word 反对的文件格式和 Docx 文档的特点;
- 如何将 Word 文档转换成 HTML 文档;
- 如何在浏览器中解决 ZIP 文档;
- 如何将 Word 文档转换成 Markdown 文档;
- 如何在前端动静生成 Word 文档。
小伙伴们筹备好了吗, 玩转 Word 文档之旅 开始了,Let’s go!
一、Microsoft Office Word 简介
Microsoft Office Word 是微软公司的一个文字处理器应用程序。它最后是由 Richard Brodie 为了运行 DOS 的 IBM 计算机而在 1983 年编写的。随后的版本可运行于 Apple Macintosh(1984 年)、SCO UNIX 和 Microsoft Windows(1989 年),并成为了 Microsoft Office 的一部分。
Word 给用户提供了用于创立业余而优雅的文档工具,帮忙用户节省时间,并失去优雅好看的后果。始终以来,Microsoft Office Word 都是最风行的文字处理程序。
1.1 Word 反对的文件格式
下表列出了常见的几种 Word 反对的文件格式,按扩展名的字母程序排序。
若想理解 Word 所有反对的格局,可参考微软 office-file-format-reference 在线文档。目前大家接触比拟多的是扩大名为 .docx
的文档,因而它就是本文的配角。
1.2 Docx 文档
俗话说“知己知彼屡战屡败”,在“出战”前咱们先来简略理解一下 docx 文档。97-2003 的旧版本文件名后缀就是 .doc,2007 版当前的后缀名是 .docx。docx 格局是被压缩过的文档,体积更小,能解决更加简单的内容,访问速度更快。
实际上 docx 文档是一个压缩文件(ZIP 格局)。ZIP 文件格式是一种数据压缩和文档贮存的文件格式,原名 Deflate,发明者为菲尔·卡茨(Phil Katz),他于 1989 年 1 月颁布了该格局的材料。ZIP 通常应用后缀名“.zip”,它的 MIME 格局为 application/zip。
这里阿宝哥曾经提前准备了一个蕴含阿宝哥头像和某些文本的 abao.docx 文档,接着复制一份重命名为 abao.zip,而后应用 ZIP 压缩 / 解压软件进行解压。
通过观察解压后的目录,咱们发现 Word 文档由一系列的 XML 文件和多媒体文件组成,abao.docx 文档中的阿宝哥头像,最终被解压到 word/media 目录下。上面咱们来查看一下 abao 文件夹的目录构造:
-rw-rw-r--@ 1 fer staff 1641 7 11 01:25 [Content_Types].xml
drwxr-xr-x@ 3 fer staff 96 7 11 09:41 _rels
drwxr-xr-x@ 4 fer staff 128 7 11 09:41 docProps
drwxr-xr-x@ 13 fer staff 416 7 11 09:42 word
很显著 abao 目录下含有一个 [Content_Types].xml 文件和 _rels、docProps、word 三个子目录。
-
[Content_Types].xml
:该文件用于定义外面每一个 XML 文件的内容类型; -
_rels
:该目录下个别会有一个 .rels 后缀的文件,它外面保留了这个目录下各个 Part 之间的关系。_rels
目录不止一个,它实际上是有层级的。 -
docProps
:该目录下的 XML 文件用于保留 docx 文件的属性; -
word
:该目录下蕴含了 Word 文档中的内容、字体、款式或主题等信息。
介绍完 Word 反对的文件格式和 Docx 文档,咱们开始进入正题 —— “在前端如何玩转 Word 文档”。
二、Word 文档转换成 HTML 文档
在日常工作中,有些时候咱们心愿在富文本编辑器中导入已有的 Word 文档进行二次加工,要满足这个需要,咱们就须要先把 Word 文档转换成 HTML 文档。要实现这个性能,有 服务端转换和前端转换 两种计划:
- 服务端转换:对于 Java 开发者来说,能够间接基于 POI 我的项目,POI 是 Apache 的一个开源我的项目,它的初衷是解决基于 Office Open XML 规范(OOXML)和 Microsoft OLE 2 复合文档格局(OLE2)的各种文件格式的文档,而且反对读写操作。
- 前端转换:对于前端开发者来说,要想在前端解析 Word 文档,咱们首先须要对 Word 文档进行解压,而后再进一步解析解压后的 XML 文档。看起来整个性能实现起来比拟繁琐,但值得庆幸的是 Mammoth.js 这个库曾经为咱们实现上述性能。
在介绍如何利用 Mammoth.js 把之前创立的 Word 文档转换成 HTML 文档前,咱们来提前体验一下最终的转换成果。
2.1 Mammoth.js 简介
Mammoth.js 旨在转换 .docx 文档(例如由 Microsoft Word 创立的文档),并将其转换为 HTML。Mammoth 的指标是通过应用文档中的语义信息并疏忽其余细节来生成简略洁净的 HTML。 比方,Mammoth 会将利用题目 1 款式的任何段落转换为 h1 元素,而不是尝试齐全复制题目的款式(字体,文本大小,色彩等)。
因为 .docx 应用的构造与 HTML 的构造之间存在很大的不匹配,这意味着对于较简单的文档而言,这种转换不太可能是完满的。但如果你仅应用款式在语义上标记文档,则 Mammoth 能实现较好的转换成果。
以后 Mammoth 反对以下次要个性:
- Headings
- Lists,Table
- Images
- Bold, italics, underlines, strikethrough, superscript and subscript
- Links,Line breaks
- Footnotes and endnotes
它还反对自定义映射规定。例如,你能够通过提供适当的款式映射将 WarningHeading 转换为 h1.warning。另外文本框的内容被视为独自的段落,呈现在蕴含文本框的段落之后。
Mammoth.js 这个库为咱们提供了很多办法,这里咱们来介绍三个比拟罕用的 API:
-
mammoth.convertToHtml(input, options)
:把源文档转换为 HTML 文档 -
mammoth.convertToMarkdown(input, options)
:把源文档转换为 Markdown 文档。这个办法与convertToHtml
办法相似,区别就是返回的 result 对象的 value 属性是 Markdown 而不是 HTML。 -
mammoth.extractRawText(input)
:提取文档的原始文本。这将疏忽文档中的所有格局。每个段落后跟两个换行符。
介绍完 Mammoth.js 相干的个性和 API,接下来咱们开始进入实战环节。
2.2 Mammoth.js 实战
Mammoth.js 这个库同时反对 Node.js 和浏览器两个平台,在浏览器端 mammoth.convertToHtml
办法的 input 参数的格局是 {arrayBuffer: arrayBuffer}
,其中 arrayBuffer 就是 .docx 文件的内容。在前端咱们能够通过 FileReader API 来读取文件的内容,此外该接口也提供了 readAsArrayBuffer 办法,用于读取指定的 Blob 中的内容,一旦读取实现,result 属性中保留的将是被读取文件的 ArrayBuffer
数据对象。上面咱们定义一个 readFileInputEventAsArrayBuffer 办法:
export function readFileInputEventAsArrayBuffer(event, callback) {const file = event.target.files[0];
const reader = new FileReader();
reader.onload = function(loadEvent: Event) {const arrayBuffer = loadEvent.target["result"];
callback(arrayBuffer);
};
reader.readAsArrayBuffer(file);
}
该办法用于实现把输出的 File 对象转换为 ArrayBuffer 对象。在获取 Word 文档对应的 ArrayBuffer 对象之后,就能够调用 convertToHtml 办法,把 Word 文档内容转换为 HTML 文档。
mammoth.convertToHtml({arrayBuffer})
此时如果你的文档中不包含非凡的图片类型,比方 wmf
或 emf
类型,而是常见的 jpg
或 png
等类型的话,那么你能够看到 Word 文档中的图片。难道这样就搞定了,那是不是太简略了,其实这只是个开始。当你通过浏览器的开发者工具审查 Word 解析后的 HTML 文档后,会发现图片都以 Base64 的格局进行嵌入。如果图片不多且单张图片也不会太大的话,那这种计划是能够思考的。
针对多图或大图的状况,一种比拟好的计划是把图片提交到文件资源服务器上。在 Mammoth.js 中要实现上述的性能,能够应用 convertImage 配置选项来自定义图片处理器。具体的应用示例如下:
let options = {convertImage: mammoth.images.imgElement(function(image) {return image.read("base64").then(function(imageBuffer) {
return {src: "data:" + image.contentType + ";base64," + imageBuffer};
});
})
};
以上示例实现的性能就是把 Word 中的图片进行 Base64 编码,而后转成 Data URL 的模式,以实现图片的显示。很显著这不合乎咱们的要求,所以咱们须要做以下调整:
const mammothOptions = {convertImage: mammoth.images.imgElement(function(image) {return image.read("base64").then(async (imageBuffer) => {const result = await uploadBase64Image(imageBuffer, image.contentType);
return {src: result.data.path // 获取图片线上的 URL 地址};
});
})
};
顾名思义 uploadBase64Image 办法的作用就是上传 Base64 编码后的图片:
async function uploadBase64Image(base64Image, mime) {const formData = new FormData();
formData.append("file", base64ToBlob(base64Image, mime));
return await axios({
method: "post",
url: "http://localhost:3000/uploadfile", // 本地图片上传的 API 地址
data: formData,
config: {headers: { "Content-Type": "multipart/form-data"} }
});
}
为了缩小图片文件的大小,咱们须要把 Base64 格局的图片先转成 Blob 对象,而后在通过创立 FormData 对象进行提交。base64ToBlob 办法的定义如下:
function base64ToBlob(base64, mimeType) {let bytes = window.atob(base64);
let ab = new ArrayBuffer(bytes.length);
let ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {ia[i] = bytes.charCodeAt(i);
}
return new Blob([ia], {type: mimeType});
}
这时把 Word 文档转换为 HTML 并主动把 Word 文档中的图片上传至文件资源服务器的基本功能曾经实现了。对于 Mammoth.js 外部是如何解析 Word 中的 XML 文件,咱们就不做介绍了,反之咱们来简略介绍一下 Mammoth.js 外部依赖的 JSZip 这个库。
2.3 JSZip 简介
JSZip 是一个用于创立、读取和编辑 .zip 文件的 JavaScript 库,含有可恶而简略的 API。该库的兼容性如下所示:
Opera | Firefox | Safari | Chrome | Internet Explorer | Node.js |
---|---|---|---|---|---|
Yes | Yes | Yes | Yes | Yes | Yes |
通过最新版本的测试 | 通过 3.0/3.6/ 最新版本测试 | 通过最新版本的测试 | 通过最新版本的测试 | 通过 IE 6 / 7 / 8 / 9 / 10 测试 | 通过 Node.js 0.10 / 最新版本测试 |
2.3.1 JSZip 装置
应用 JSZip 时,你能够通过以下几种形式进行装置:
-
npm:
npm install jszip
-
bower:
bower install Stuk/jszip
-
component:
component install Stuk/jszip
-
手动 :先下载 JSZip 安装包,而后引入
dist/jszip.js
或dist/jszip.min.js
文件
2.3.2 JSZip 应用示例
let zip = new JSZip();
zip.file("Hello.txt", "Hello Semlinker\n");
let img = zip.folder("images");
img.file("smile.gif", imgData, {base64: true});
zip.generateAsync({type: "blob"})
.then(function(content) {
// see FileSaver.js
saveAs(content, "example.zip");
});
该示例来自 JSZip 官网,胜利运行之后,会主动下载并保留 example.zip 文件。该文件解压后的目录构造如下所示:
三、Word 文档转换成 Markdown 文档
Markdown 是一种轻量级标记语言 ,创始人为约翰·格鲁伯(英语:John Gruber)。它容许人们应用易读易写的纯文本格式编写文档,而后转换成无效的 XHTML(或者 HTML)文档。这种语言排汇了很多在电子邮件中已有的纯文本标记的个性。
因为 Markdown 的轻量化、易读易写个性,并且对于图片,图表、数学式都有反对,目前许多网站都宽泛应用 Markdown 来撰写帮忙文档或是用于论坛上发表音讯。
理解完 Markdown 是什么之后,咱们来剖析一下如何把 Word 文档转换成 Markdown 文档。对于这个性能,咱们也有两种解决形式:
- 第一种:应用 Mammoth.js 这个库提供的
mammoth.convertToMarkdown(input, options)
办法; - 第二种:基于
mammoth.convertToHtml(input, options)
生成的 HTML 文档,在利用 HTML to Markdown 的转换工具,来间接实现上述性能。
上面咱们来介绍第二种计划,这里咱们应用 Github 上一个开源的转换器 —— turndown,它是应用 JavaScript 开发的 HTML to Markdown 转换器,应用起来很简略。
首先你能够通过以下两种形式来装置它:
- npm:
npm install turndown
- script:
<script src="https://unpkg.com/turndown/dist/turndown.js"></script>
装置完之后,你就能够通过调用 TurndownService
构造函数,来创立 turndownService 实例,而后调用该实例的 turndown()
办法执行转换操作:
let markdown = turndownService.turndown(document.getElementById('content')
)
对于后面应用的 abao.docx 文档,最终转换生成的 Markdown 文档如下:
全栈修仙之路,聚焦全栈,专一分享 TypeScript、Web API、Node.js、Deno 等全栈干货。![](https://cdn.xxx.com/rich_159444942843202)
须要留神的是,TurndownService 构造函数反对很多配置项,这里阿宝哥就不具体介绍了。感兴趣的小伙伴,能够自行浏览 turndown 官网文档或拜访 turndown 在线示例 理论体验一下。
既然曾经讲到 Markdown,阿宝哥再给小伙伴们介绍一个 Github 上不错的开源库 markmap,该库应用思维导图的形式来实现 Markdown 文档的可视化,整体成果还蛮不错的:
(图片起源:https://markmap.js.org/repl/)
最初,咱们再来看一下在前端如何动静生成 Word 文档。
四、前端动静生成 Word 文档
在前端如果要动静生成 Word 文档,咱们能够间接利用一些成熟的第三方开源库,比方:docx 或 html-docx-js。
上面咱们将以 docx 为例,来介绍如何在前端如何生成 .docx 格局的 Word 文档。Docx 这个库提供了优雅的申明式 API,让咱们能够应用 JS/TS 轻松生成 .docx 文件。此外,它还同时反对 Node.js 和浏览器。
Docx 这个库为开发者提供了许多类,用于创立 Word 中的对应元素,这里咱们简略介绍几个常见的类:
- Document:用于创立新的 Word 文档;
- Paragraph:用于创立新的段落;
- TextRun:用于创立文本,反对设置加粗、斜体和下划线款式;
- Tables:用于创建表格,反对设置表格每一行和每个表格单元的内容。
接下来阿宝哥将应用 Docx 这个库,来动静生成后面介绍过的 abao.docx 文档,具体代码如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<h1> 阿宝哥 - 动静生成 Word 文档示例 </h1>
<button type="button" onclick="generate()">
点击生成 Docx 文档
</button>
<script src="https://unpkg.com/docx@5.0.2/build/index.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
<script>
async function generate() {const doc = new docx.Document();
const imageBuffer = await fetch("https://avatars3.githubusercontent.com/u/4220799").then((response) => response.arrayBuffer());
const image = docx.Media.addImage(doc, imageBuffer, 230, 230);
doc.addSection({properties: {},
children: [
new docx.Paragraph({
children: [
new docx.TextRun({
text: "全栈修仙之路,",
bold: true,
}),
new docx.TextRun({
text:
"聚焦全栈,专一分享 TypeScript、Web API、Node.js、Deno 等全栈干货。",
}),
],
}),
new docx.Paragraph(image),
],
});
docx.Packer.toBlob(doc).then((blob) => {console.log(blob);
saveAs(blob, "abao.docx");
console.log("文档生成胜利");
});
}
</script>
</body>
</html>
在以上示例中,当用户点击 点击生成 Docx 文档 按钮之后,会调用 generate()
回调函数。在该回调函数内,首先会创立新的 Document 对象,而后应用 fetch API 从 Github 上下载阿宝哥的头像,当胜利获取图片的数据之后,会持续调用 docx.Media.addImage()
办法增加图片。
接着咱们会调用 doc.addSection()
办法来增加 Section 块,该块将作为段落的容器。在示例中,咱们创立的 Section 块蕴含两个段落,一个用于寄存文本信息,而另一个用于寄存图片信息。最初咱们会把 Document 对象转换成 Blob 对象,而后通过 saveAs()
办法下载到本地。
五、参考资源
- MDN – FileReader
- 百度百科 – Microsoft Office Word
- office-file-format-reference
- Github – mammoth.js