前端处理 word/zip 文档

| mammoth:Word 文档转换 Html/markdown

mammoth.js 的目标是通过使用文档中的语义信息并忽略其他细节来生成简单干净的 HTML。安装:npm install mammoth

Mammoth.js 常用 API:

  1. mammoth.convertToHtml(input, options):把源文档转换为 HTML 文档
  2. mammoth.convertToMarkdown(input, options):把源文档转换为 Markdown 文档
  3. mammoth.extractRawText(input):提取文档的原始文本

在浏览器端 mammoth.convertToHtml 方法的 input 参数的格式是 {arrayBuffer: arrayBuffer},其中 arrayBuffer 就是 .docx 文件的内容。

案例:选择本地 word 文档,把选择的 File 对象转换为 ArrayBuffer 对象,调用 convertToHtml 方法,把 Word 文档内容转换为 HTML 文档,并在当前页面展示

inputChange(event) {
  const file = event.target.files[0];
  const reader = new FileReader();
  let _this = this;
  reader.onload = function (loadEvent) {
    const arrayBuffer = loadEvent.target["result"];
    mammoth.convertToHtml({ arrayBuffer }).then((res) => {
      _this.result = res.value
    }).done()
  };
  reader.readAsArrayBuffer(file);
}

解析后的 HTML 文档中图片都以 Base64 的格式进行嵌入。如果图片不多且单张图片也不会太大的话,那这种方案是可以考虑的。针对多图或大图的情况,一种比较好的方案是把图片提交到文件资源服务器上。在 Mammoth.js 中要实现上述的功能,可以使用 「convertImage」 配置选项来自定义图片处理器。

const options = {
  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地址
      };
    });
  }),
};
// 上传 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 对象,然后提交
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 });
}
// 转换
mammoth
  .convertToHtml({ arrayBuffer }, options)
  .then((res) => {
    this.result = res.value;
  })
  .done();

| JSZip/FileSaver:生成 zip 文件下载

jszip 是一个用于创建、读取和编辑.zip 文件的 JavaScript 库,且 API 的使用也很简单。安装: npm install jszipnpm install file-saver

案例:JSZip 使用示例-自动下载并保存 「example.zip」 文件

import JSZip from 'jszip';
import FileSaver from 'file-saver';
let zip = new JSZip(); // 创建一个JSZip实例
// 使用.file(fileName,fileContent)添加一个txt文件
zip.file('Hello.txt', 'Hello Semlinker\n');
// 使用.folder(folderName)添加一个文件夹
let img = zip.folder('images');
// 使用.file(fileName,fileContent,base64FLag)在文件夹下添加一个图片文件, 注:fileContent可以是File文件也可以是Blob二进制数据
img.file('smile.gif', imgData, { base64: true });
// 生成一个zip文件
zip.generateAsync({ type: 'blob' }).then(function (content) {
  // see FileSaver.js
  FileSaver.saveAs(content, 'example.zip');
});
// type:"blob" 压缩的结果为二进制流,可用作文件上传saveAs(content, "example.zip"); 直接在浏览器打成example.zip包并下载,saveAs依赖的js是FileSaver.js

| turndown:HTML 转 Markdown

npm install turndown

import TurndownService from 'turndown';
var turndownService = new TurndownService();
let markdown = turndownService.turndown(`<p>aa</p>`);

| 动态生成 word 文档

在前端如果要动态生成 Word 文档,我们可以直接利用一些成熟的第三方开源库,比如:docx 或 html-docx-js。

Docx 这个库为开发者提供了许多类,用于创建 Word 中的对应元素,这里我们简单介绍几个常见的类:

  • Document:用于创建新的 Word 文档;
  • Paragraph:用于创建新的段落;
  • TextRun:用于创建文本,支持设置加粗、斜体和下划线样式;
  • Tables:用于创建表格,支持设置表格每一行和每个表格单元的内容。
// <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>

 async 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("文档生成成功");
  });
}

参考链接:前端如何玩转 Word 文档