在前端如何玩转 Word 文档
在日常工作中,大部分人都會(huì)使用 Microsoft Office Word、WPS 或 macOS Pages 等文字處理程序進(jìn)行 Word 文檔處理。除了使用上述的文字處理程序之外,對(duì)于 Word 文檔來說,還有其他的處理方式么?答案是有的。
接下來阿寶哥將介紹在前端如何玩轉(zhuǎn) Word 文檔,閱讀本文之后,你將了解以下內(nèi)容:
Microsoft Office Word 支持的文件格式和 Docx 文檔的特點(diǎn);
如何將 Word 文檔轉(zhuǎn)換成 HTML 文檔;
如何在瀏覽器中處理 ZIP 文檔;
如何將 Word 文檔轉(zhuǎn)換成 Markdown 文檔;
如何在前端動(dòng)態(tài)生成 Word 文檔。
小伙伴們準(zhǔn)備好了嗎,「玩轉(zhuǎn) Word 文檔之旅」 開始了,Let's go!
一、Microsoft Office Word 簡介
Microsoft Office Word 是微軟公司的一個(gè)文字處理器應(yīng)用程序。它最初是由 Richard Brodie 為了運(yùn)行 DOS 的 IBM 計(jì)算機(jī)而在 1983 年編寫的。隨后的版本可運(yùn)行于 Apple Macintosh(1984 年)、SCO UNIX 和 Microsoft Windows(1989 年),并成為了 Microsoft Office 的一部分。
Word 給用戶提供了用于創(chuàng)建專業(yè)而優(yōu)雅的文檔工具,幫助用戶節(jié)省時(shí)間,并得到優(yōu)雅美觀的結(jié)果。一直以來,Microsoft Office Word 都是最流行的文字處理程序。
1.1 Word 支持的文件格式
下表列出了常見的幾種 Word 支持的文件格式,按擴(kuò)展名的字母順序排序。
若想了解 Word 所有支持的格式,可參考微軟 office-file-format-reference 在線文檔。目前大家接觸比較多的是擴(kuò)展名為 .docx 的文檔,因此它就是本文的主角。
1.2 Docx 文檔
俗話說 “知己知彼百戰(zhàn)百勝”,在 “出戰(zhàn)” 前我們先來簡單了解一下 「docx」 文檔。「97-2003 的舊版本文件名后綴就是 .doc, 2007 版以后的后綴名是 .docx」。docx 格式是被壓縮過的文檔,體積更小,能處理更加復(fù)雜的內(nèi)容,訪問速度更快。
實(shí)際上 「docx」 文檔是一個(gè)壓縮文件( ZIP 格式)。ZIP 文件格式是一種數(shù)據(jù)壓縮和文檔儲(chǔ)存的文件格式,原名 Deflate,發(fā)明者為菲爾·卡茨(Phil Katz),他于 1989 年 1 月公布了該格式的資料。ZIP 通常使用后綴名 “.zip”,它的 MIME 格式為 「application/zip」。
這里阿寶哥已經(jīng)提前準(zhǔn)備了一個(gè)包含阿寶哥頭像和某些文本的 「abao.docx」 文檔,接著復(fù)制一份重命名為 「abao.zip」,然后使用 ZIP 壓縮/解壓軟件進(jìn)行解壓。
通過觀察解壓后的目錄,我們發(fā)現(xiàn) Word 文檔由一系列的 XML 文件和多媒體文件組成, 「abao.docx」 文檔中的阿寶哥頭像,最終被解壓到 「word/media」 目錄下。下面我們來查看一下 abao 文件夾的目錄結(jié)構(gòu):
-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 目錄下含有一個(gè) 「[Content_Types].xml」 文件和 「_rels、docProps、word」 三個(gè)子目錄。
[Content_Types].xml:該文件用于定義里面每一個(gè) XML 文件的內(nèi)容類型;
_rels:該目錄下一般會(huì)有一個(gè) 「.rels」 后綴的文件,它里面保存了這個(gè)目錄下各個(gè) Part 之間的關(guān)系。_rels 目錄不止一個(gè),它實(shí)際上是有層級(jí)的。
docProps:該目錄下的 XML 文件用于保存 docx 文件的屬性;
word:該目錄下包含了 Word 文檔中的內(nèi)容、字體、樣式或主題等信息。
介紹完 Word 支持的文件格式和 Docx 文檔,我們開始進(jìn)入正題 —— 「“在前端如何玩轉(zhuǎn) Word 文檔”」。
二、Word 文檔轉(zhuǎn)換成 HTML 文檔
在日常工作中,有些時(shí)候我們希望在富文本編輯器中導(dǎo)入已有的 Word 文檔進(jìn)行二次加工,要滿足這個(gè)需求,我們就需要先把 Word 文檔轉(zhuǎn)換成 HTML 文檔。要實(shí)現(xiàn)這個(gè)功能,有 「服務(wù)端轉(zhuǎn)換和前端轉(zhuǎn)換」 兩種方案:
服務(wù)端轉(zhuǎn)換:對(duì)于 Java 開發(fā)者來說,可以直接基于 POI 項(xiàng)目,POI 是 Apache 的一個(gè)開源項(xiàng)目,它的初衷是處理基于 Office Open XML 標(biāo)準(zhǔn)(OOXML)和 Microsoft OLE 2 復(fù)合文檔格式(OLE2)的各種文件格式的文檔,而且支持讀寫操作。
前端轉(zhuǎn)換:對(duì)于前端開發(fā)者來說,要想在前端解析 Word 文檔,我們首先需要對(duì) Word 文檔進(jìn)行解壓,然后再進(jìn)一步解析解壓后的 XML 文檔。看起來整個(gè)功能實(shí)現(xiàn)起來比較繁瑣,但值得慶幸的是 Mammoth.js 這個(gè)庫已經(jīng)為我們實(shí)現(xiàn)上述功能。
在介紹如何利用 Mammoth.js 把之前創(chuàng)建的 Word 文檔轉(zhuǎn)換成 HTML 文檔前,我們來提前體驗(yàn)一下最終的轉(zhuǎn)換效果。
2.1 Mammoth.js 簡介
Mammoth.js 旨在轉(zhuǎn)換 .docx 文檔(例如由 Microsoft Word 創(chuàng)建的文檔),并將其轉(zhuǎn)換為 HTML。「Mammoth 的目標(biāo)是通過使用文檔中的語義信息并忽略其他細(xì)節(jié)來生成簡單干凈的 HTML。」 比如,Mammoth 會(huì)將應(yīng)用標(biāo)題 1 樣式的任何段落轉(zhuǎn)換為 h1 元素,而不是嘗試完全復(fù)制標(biāo)題的樣式(字體,文本大小,顏色等)。
由于 .docx 使用的結(jié)構(gòu)與 HTML 的結(jié)構(gòu)之間存在很大的不匹配,這意味著對(duì)于較復(fù)雜的文檔而言,這種轉(zhuǎn)換不太可能是完美的。但如果你僅使用樣式在語義上標(biāo)記文檔,則 Mammoth 能實(shí)現(xiàn)較好的轉(zhuǎn)換效果。
當(dāng)前 Mammoth 支持以下主要特性:
Headings
Lists,Table
Images
Bold, italics, underlines, strikethrough, superscript and subscript
Links,Line breaks
Footnotes and endnotes
它還支持自定義映射規(guī)則。例如,你可以通過提供適當(dāng)?shù)臉邮接成鋵?WarningHeading 轉(zhuǎn)換為 h1.warning。另外文本框的內(nèi)容被視為單獨(dú)的段落,出現(xiàn)在包含文本框的段落之后。
Mammoth.js 這個(gè)庫為我們提供了很多方法,這里我們來介紹三個(gè)比較常用的 API:
mammoth.convertToHtml(input, options):把源文檔轉(zhuǎn)換為 HTML 文檔
mammoth.convertToMarkdown(input, options):把源文檔轉(zhuǎn)換為 Markdown 文檔。這個(gè)方法與 convertToHtml 方法類似,區(qū)別就是返回的 result 對(duì)象的 value 屬性是 Markdown 而不是 HTML。
mammoth.extractRawText(input):提取文檔的原始文本。這將忽略文檔中的所有格式。每個(gè)段落后跟兩個(gè)換行符。
介紹完 Mammoth.js 相關(guān)的特性和 API,接下來我們開始進(jìn)入實(shí)戰(zhàn)環(huán)節(jié)。
2.2 Mammoth.js 實(shí)戰(zhàn)
Mammoth.js 這個(gè)庫同時(shí)支持 Node.js 和瀏覽器兩個(gè)平臺(tái),在瀏覽器端 mammoth.convertToHtml 方法的 input 參數(shù)的格式是 {arrayBuffer: arrayBuffer},其中 arrayBuffer 就是 .docx 文件的內(nèi)容。在前端我們可以通過 FileReader API ?來讀取文件的內(nèi)容,此外該接口也提供了 readAsArrayBuffer 方法,用于讀取指定的 Blob 中的內(nèi)容,一旦讀取完成,result 屬性中保存的將是被讀取文件的 ArrayBuffer 數(shù)據(jù)對(duì)象。下面我們定義一個(gè) 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); }該方法用于實(shí)現(xiàn)把輸入的 File 對(duì)象轉(zhuǎn)換為 ArrayBuffer 對(duì)象。在獲取 Word 文檔對(duì)應(yīng)的 ArrayBuffer 對(duì)象之后,就可以調(diào)用 convertToHtml 方法,把 Word 文檔內(nèi)容轉(zhuǎn)換為 HTML 文檔。
mammoth.convertToHtml({?arrayBuffer?})此時(shí)如果你的文檔中不包括特殊的圖片類型,比如 wmf 或 emf 類型,而是常見的 jpg 或 png 等類型的話,那么你可以看到 Word 文檔中的圖片。難道這樣就搞定了,那是不是太簡單了,其實(shí)這只是個(gè)開始。當(dāng)你通過瀏覽器的開發(fā)者工具審查 Word 解析后的 HTML 文檔后,會(huì)發(fā)現(xiàn)圖片都以 Base64 的格式進(jìn)行嵌入。如果圖片不多且單張圖片也不會(huì)太大的話,那這種方案是可以考慮的。
針對(duì)多圖或大圖的情況,一種比較好的方案是把圖片提交到文件資源服務(wù)器上。在 Mammoth.js 中要實(shí)現(xiàn)上述的功能,可以使用 「convertImage」 配置選項(xiàng)來自定義圖片處理器。具體的使用示例如下:
let?options?=?{convertImage:?mammoth.images.imgElement(function(image)?{return?image.read("base64").then(function(imageBuffer)?{return?{src:?"data:"?+?image.contentType?+?";base64,"?+?imageBuffer};});}) };以上示例實(shí)現(xiàn)的功能就是把 Word 中的圖片進(jìn)行 Base64 編碼,然后轉(zhuǎn)成 Data URL 的形式,以實(shí)現(xiàn)圖片的顯示。很明顯這不符合我們的要求,所以我們需要做以下調(diào)整:
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 格式的圖片先轉(zhuǎn)成 Blob 對(duì)象,然后在通過創(chuàng)建 FormData 對(duì)象進(jìn)行提交。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?}); }這時(shí)把 Word 文檔轉(zhuǎn)換為 HTML 并自動(dòng)把 Word 文檔中的圖片上傳至文件資源服務(wù)器的基本功能已經(jīng)實(shí)現(xiàn)了。對(duì)于 Mammoth.js 內(nèi)部是如何解析 Word 中的 XML 文件,我們就不做介紹了,反之我們來簡單介紹一下 Mammoth.js 內(nèi)部依賴的 JSZip 這個(gè)庫。
2.3 JSZip 簡介
JSZip 是一個(gè)用于創(chuàng)建、讀取和編輯 「.zip」 文件的 JavaScript 庫,含有可愛而簡單的 API。該庫的兼容性如下所示:
| Yes | Yes | Yes | Yes | Yes | Yes |
| 經(jīng)過最新版本的測試 | 經(jīng)過 3.0/3.6/最新版本測試 | 經(jīng)過最新版本的測試 | 經(jīng)過最新版本的測試 | 經(jīng)過 IE 6 / 7 / 8 / 9 / 10 測試 | 經(jīng)過 Node.js 0.10 / 最新版本測試 |
2.3.1 JSZip 安裝
使用 JSZip 時(shí),你可以通過以下幾種方式進(jìn)行安裝:
「npm」:npm install jszip
「bower」:bower install Stuk/jszip
「component」 :component install Stuk/jszip
「手動(dòng)」:先下載 ?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.jssaveAs(content,?"example.zip"); });該示例來自 JSZip 官網(wǎng),成功運(yùn)行之后,會(huì)自動(dòng)下載并保存 「example.zip」 文件。該文件解壓后的目錄結(jié)構(gòu)如下所示:
三、Word 文檔轉(zhuǎn)換成 Markdown 文檔
「Markdown 是一種輕量級(jí)標(biāo)記語言」 ,創(chuàng)始人為約翰·格魯伯(英語:John Gruber)。它允許人們使用易讀易寫的純文本格式編寫文檔,然后轉(zhuǎn)換成有效的 XHTML(或者 HTML)文檔。這種語言吸收了很多在電子郵件中已有的純文本標(biāo)記的特性。
由于 Markdown 的輕量化、易讀易寫特性,并且對(duì)于圖片,圖表、數(shù)學(xué)式都有支持,目前許多網(wǎng)站都廣泛使用 Markdown 來撰寫幫助文檔或是用于論壇上發(fā)表消息。
了解完 Markdown 是什么之后,我們來分析一下如何把 Word 文檔轉(zhuǎn)換成 Markdown 文檔。對(duì)于這個(gè)功能,我們也有兩種處理方式:
第一種:使用 Mammoth.js 這個(gè)庫提供的 mammoth.convertToMarkdown(input, options) 方法;
第二種:基于 mammoth.convertToHtml(input, options) 生成的 HTML 文檔,在利用 HTML to Markdown 的轉(zhuǎn)換工具,來間接實(shí)現(xiàn)上述功能。
下面我們來介紹第二種方案,這里我們使用 Github 上一個(gè)開源的轉(zhuǎn)換器 —— ?turndown,它是使用 JavaScript 開發(fā)的 HTML to Markdown 轉(zhuǎn)換器,使用起來很簡單。
首先你可以通過以下兩種方式來安裝它:
npm:npm install turndown
script:<script src="https://unpkg.com/turndown/dist/turndown.js"></script>
安裝完之后,你就可以通過調(diào)用 TurndownService 構(gòu)造函數(shù),來創(chuàng)建 turndownService 實(shí)例,然后調(diào)用該實(shí)例的 turndown() 方法執(zhí)行轉(zhuǎn)換操作:
let?markdown?=?turndownService.turndown(document.getElementById('content') )對(duì)于前面使用的 「abao.docx」 文檔,最終轉(zhuǎn)換生成的 Markdown 文檔如下:
全棧修仙之路,聚焦全棧,專注分享 TypeScript、Web API、Node.js、Deno 等全棧干貨。需要注意的是,TurndownService 構(gòu)造函數(shù)支持很多配置項(xiàng),這里阿寶哥就不詳細(xì)介紹了。感興趣的小伙伴,可以自行閱讀 turndown 官方文檔或訪問 turndown 在線示例 實(shí)際體驗(yàn)一下。
既然已經(jīng)講到 Markdown,阿寶哥再給小伙伴們介紹一個(gè) Github 上不錯(cuò)的開源庫 markmap,該庫使用思維導(dǎo)圖的方式來實(shí)現(xiàn) Markdown 文檔的可視化,整體效果還蠻不錯(cuò)的:
(圖片來源:https://markmap.js.org/repl/)
最后,我們再來看一下在前端如何動(dòng)態(tài)生成 Word 文檔。
四、前端動(dòng)態(tài)生成 Word 文檔
在前端如果要?jiǎng)討B(tài)生成 Word 文檔,我們可以直接利用一些成熟的第三方開源庫,比如:docx 或 html-docx-js。
下面我們將以 docx 為例,來介紹如何在前端如何生成 「.docx」 格式的 Word 文檔。Docx 這個(gè)庫提供了優(yōu)雅的聲明式 API,讓我們可以使用 JS/TS 輕松生成 .docx 文件。此外,它還同時(shí)支持 Node.js 和瀏覽器。
Docx 這個(gè)庫為開發(fā)者提供了許多類,用于創(chuàng)建 Word 中的對(duì)應(yīng)元素,這里我們簡單介紹幾個(gè)常見的類:
Document:用于創(chuàng)建新的 Word 文檔;
Paragraph:用于創(chuàng)建新的段落;
TextRun:用于創(chuàng)建文本,支持設(shè)置加粗、斜體和下劃線樣式;
Tables:用于創(chuàng)建表格,支持設(shè)置表格每一行和每個(gè)表格單元的內(nèi)容。
接下來阿寶哥將使用 Docx 這個(gè)庫,來動(dòng)態(tài)生成前面介紹過的 「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>阿寶哥?-?動(dòng)態(tài)生成?Word?文檔示例</h1><button?type="button"?onclick="generate()">點(diǎn)擊生成?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>在以上示例中,當(dāng)用戶點(diǎn)擊 「點(diǎn)擊生成 Docx 文檔」 按鈕之后,會(huì)調(diào)用 generate() 回調(diào)函數(shù)。在該回調(diào)函數(shù)內(nèi),首先會(huì)創(chuàng)建新的 Document 對(duì)象,然后使用 fetch API 從 Github 上下載阿寶哥的頭像,當(dāng)成功獲取圖片的數(shù)據(jù)之后,會(huì)繼續(xù)調(diào)用 docx.Media.addImage() 方法添加圖片。
接著我們會(huì)調(diào)用 doc.addSection() 方法來添加 Section 塊,該塊將作為段落的容器。在示例中,我們創(chuàng)建的 Section 塊包含兩個(gè)段落,一個(gè)用于存放文本信息,而另一個(gè)用于存放圖片信息。最后我們會(huì)把 Document 對(duì)象轉(zhuǎn)換成 Blob 對(duì)象,然后通過 saveAs() 方法下載到本地。
五、參考資源
MDN - FileReader
百度百科 - Microsoft Office Word
office-file-format-reference
Github - mammoth.js
關(guān)于奇舞周刊
《奇舞周刊》是360公司專業(yè)前端團(tuán)隊(duì)「奇舞團(tuán)」運(yùn)營的前端技術(shù)社區(qū)。關(guān)注公眾號(hào)后,直接發(fā)送鏈接到后臺(tái)即可給我們投稿。
總結(jié)
以上是生活随笔為你收集整理的在前端如何玩转 Word 文档的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【pthread_cancel函数:避免
- 下一篇: 使用xcode devices安装卸载i