一键将Word文档转成Vue组件mammoth的应用详解
货拉拉技术 人气:0正文
在开发后台管理系统的过程中,经常有这样的需求:将 Word 文档(比如用户协议文档)转换为 HTML 页面(Vue 组件)。转换 Word 文档过程通常是枯燥的。开源社区的 mammoth.js 正好可以解压 .docx,并解析 XML 结构,最终将 Word 转成 HTML 文件。因此可以基于该开源库开发「Word 文档转 Vue 组件」工具,让转换流程自动化,从而有效提升了工作效率。本文介绍该工具的实现原理。
mammoth.js 的不足
mammoth.js 虽然可以直接生成 HTML 文件,但是使用过程还是遇到不少问题。比如下图所示的 Word 文档:
经过 mammoth.js 转换后的页面却是这个样子:
从上图我们可以发现以下几个问题:
- 标题栏不居中
- 本来是 Word 中的排序,却只是
<li></li>
默认样式 1 2 3 - 跟现有的协议规范样式不匹配
- 超链接没有交互
- Table 表单不符合预期
改造
因此有必要通过对 mammoth 进行定制来满足当前项目的需求。mammoth 提供了方法可以获取转换后的 AST 节点,那我们就利用这个方法,对 AST 进行转换,最后生成一份可用的 Vue 文件。整个流程如下图所示:
解析 AST
首先先获取 AST。
var options = { transformDocument: transformElement, }; mammoth.convertToHtml({ path }, options).done(async () => { // Word处理完毕 });
AST 节点
每个节点都会标明 type 类型、是否居中、字号大小、是否粗体、是否斜体、是否有下划线等。
type 类型如下所示:
Document 根节点
Paragraph 段落
- Text
- Run (这种情况,表示 mammoth 把一段话分成几小部分,所以需要拼接 children 内的 text 节点。)
- hyperlink
Table 表单
- tableRow
- tableCell
处理 AST 节点
在处理节点的过程中,有以下几个注意事项:
- Q: 何时换行?
A: 经观察,type: 'paragraph', children: []
的时候表示需要换行。
- Q: 哪些是正标题、副标题
A: 在我们项目中,把居中且字号 16 的文本定义为正标题,居中且字号 14 的文本定义为副标题。
- Q: 段落首行缩进
A: 这点需要手动处理,默认增加 4 个缩进
。
- Q: 如何处理粗体、字号、空格、超链接?
A: 粗体、字号生成公共的 class,比如'bold' 'font-size-14' 'font-size-16'
;空格需要将\s
替换为
;对于 type === 'hyperlink'的超链接,转成<a target="_blank" class="blue" href="${txt.href}">${txt.children[0].value}</a>
。
- Q: Word 文档中排序是如何转换的?
A: 用 node 节点中的numbering
字段来判断,需要排序则numbering
有值;不需要排序则numbering: null
; 维护一个公共变量保存排序数值,再将英文数字 1 2 3 等 转换为中文一、二、三等。
- Q: Table 样式如何处理?
A: 在该节点中,第一个元素为thead
标签,后续元素为tbody
标签;tbody 中的children
节点是由type: paragraph
节点构成,可以handleParagraph
递归处理。
下面的代码展示了处理段落、表单的逻辑。
function transformElement(element) { // 根节点 const document = element.children; if (Array.isArray(document)) { document.forEach((ele) => { switch (ele.type) { case 'paragraph': str += handleParagraph(ele); break; case 'table': handleTable(ele); break; default: break; } }); } return element; }
代码格式化与生成
首先将字符串拼接成为 Vue 组件源码。
const originalStr = `<template> ... </template> <script> // ... </script> <style lang="less" scoped> // ... </style>\n`;
每次给组件起名字也挺烦的,所以可以使用 translate-shell 就根据协议文档的中文名称,进行翻译得出。
// 读取word路径名,并进行翻译,自动生成template name和文件名 function getTranslatedNames(path) { return new Promise((resolve) => { const chArr = path.replace('.docx', '').split('/'); exec( `trans -t english '${chArr[chArr.length - 1]}'`, (error, stdout, stderr) => { const arr = stdout.split('\n'); // ... resolve(target.replace(/[^a-zA-Z-]/gi, '')); }, ); }); }
至此我们已经得到符合项目需求的代码,文件名称也有了,现在只需要将代码内容格式化写入文件就完成了。
// 格式化 const finalStr = prettier.format(originalStr, config); fs.writeFileSync(`${templateName}.vue`, finalStr, 'utf-8');
最终的效果如下图所示:
总结
简而言之,这个工具站在了 mammoth 的肩膀上,利用 AST 节点,再根据 UI 稿相应地做不同转换。生成符合规范的代码后,再拼接成 vue 组件,写入项目中。mammoth 处理 Word 文档还是非常方便的,推荐使用。
加载全部内容