React前端实现word导出(word表格操作,图片操作,字体颜色修改)

前言

本文使用前端框架React。
最近项目遇到一个需求,需要前端去导出word。百度了一圈后,找到了一个导出word的模版库,非常好用。
贴上地址:docxtemplater
借鉴了大佬的图片导出写法,下面贴上地址:
Word导出图片

功能点

1.导出指定排版的文章
2.导出带样式的文字
3.导出图片
4.导出表格

使用方法

首先讲一下在代码中怎么使用
首先导入第三方库:

import Docxtemplaterfrom 'docxtemplater'
import PizZipfrom 'pizzip'
import JSZipUtils from 'jszip-utils'
import { saveAs }from 'file-saver'
import ImageModule from "docxtemplater-image-module-free";

直接上代码(可直接复制):


/**

*函数传入参数说明:filepath:word保存的地址,

*wordData:word导出需要的数据,

*outPath:word导出文件名

* */

generateDocument = (filePath,wordData,outPath) => {

// 读取并获得模板文件的二进制内容,是docxtemplater提供的固定写法

  JSZipUtils.getBinaryContent(filePath, function (error, content) {

// exportTemplate.docx是模板,React写在public里。我们在导出的时候,会根据此模板来导出对应的数据

//图片导出功能

      let opts = {

        centered:false,

        fileType:"docx",

        getSize: (img, tagValue, tagName)=>{

                let width =100;

                let height =100;

                return [width,height];

        },

        getImage:(tagValue)=>{

            / /图片base64转字节数组

            return base64DataURLToArrayBuffer(tagValue)

        }

  }

let imageModule = new ImageModule(opts);

      // 创建一个PizZip实例,内容为模板的内容

      let zip =new PizZip(content);

      // 创建并加载docxtemplater实例对象

      let doc =new Docxtemplater(zip,{modules:[imageModule]}).setData(wordData)

try{

doc.render();

 }catch (error) {

 function replaceErrors(key, value) {

    if (valueinstanceof Error) {

        return Object.getOwnPropertyNames(value).reduce(function(error, key) {

        error[key] = value[key];

                  return error;

              }, {});

            }

return value;

        }

if (error.properties && error.properties.errors instanceof Array) {

const errorMessages = error.properties.errors.map(function (error) {

return error.properties.explanation;

            }).join("\n");

        }

throw error;

      }

// 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)

  let out = doc.getZip().generate({

        type : "blob",

        mimeType : "application/vnd.openxmlformats-officedocument.wordprocessingml.document"

     });

     //Output the document using Data-URI

      saveAs(out, outPath);

  })

}

//图片转base64字节码

function base64DataURLToArrayBuffer(dataURL) {

const base64Regex =/^data:image\/(png|jpg|svg|jpeg|svg\+xml);base64,/;

  if (!base64Regex.test(dataURL)) {

return false;

  }

const stringBase64 = dataURL.replace(base64Regex, "");

  let binaryString;

  if (typeof window !=="undefined") {

binaryString =window.atob(stringBase64);

  }else {

binaryString =new Buffer(stringBase64, "base64").toString("binary");

  }

const len = binaryString.length;

  const bytes =new Uint8Array(len);

  for (let i =0; i < len; i++) {

const ascii = binaryString.charCodeAt(i);

      bytes[i] = ascii;

  }

return bytes.buffer;

}

问题说明

JSZipUtils读取文件操作:

如果你的JSZipUtils读取不到word路径,你可以把文件放在public文件夹下。如果你的项目没有public文件夹。

1.重新创建项目

2.你可以把word放在src文件夹下任意文字

image

然后你需要在打包文件中指定word文件上传后读取的位置,不然打包发布后服务器读取不到文件

具体操作如下:

我的打包文件:

image

导入一个第三方库:const CopyWebpackPlugin = require(‘copy-webpack-plugin’);

在module.exports的plugins下加入

new CopyWebpackPlugin([

// {

//    from: './src/MP_verify_Jf3BC19m68lvFLyl.txt',

//    to: path.join(__dirname, '../dist/')

// },

  {

from:'./src/word/1.docx',

      to:path.join(__dirname, '../dist/')

},{

from:'./src/word/dz.docx',

      to:path.join(__dirname, '../dist/')

},{

from:'./src/word/hx.docx',

      to:path.join(__dirname, '../dist/')

},{

from:'./src/reports/x-text-1.html',

      to:path.join(__dirname, '../dist/')

}

]),

如图所示

image

dist为build打包生成的文件

word模版讲解

代码加载word操作已经讲完了,下面轮到word模版和数据处理了。

首先wordData传递的数据是object键值对类型的数据。具体可看官方文档docxtemplater

1.排版

如果你需要插入固定格式的文字,例如下面这种

image

第一种模版写法为:

{-w:p products}{title}{/products}

数据格式:products:[{title:‘name’}]

第二种模版写法:

{#products}{.}{/products}

数据格式:products:[‘name’]

具体使用那种看你的数据格式

2.带格式的文本

image

如这种正数为红色,负数为绿色。

需要插入xml格式

模版非常简单,直接加上@就行了,如{@name1}

代码则需要插入docxXml格式

直接上代码


static indexInformationToXML = (color,content) =>{

return (

`<w:p>

        <w:pPr>

            <w:widowControl/>

            <w:jc w:val="center"/>

            <w:textAlignment w:val="center"/>

            <w:rPr>

              <w:rFonts w:ascii="楷体"

                      w:hAnsi="楷体"

                      w:eastAsia="楷体"

                      w:cs="楷体"/>

              <w:color w:val="000000"/>

              <w:sz w:val="20"/>

              <w:szCs w:val="20"/>

            </w:rPr>

        </w:pPr>

        <w:r>

        <w:rPr>

        <w:rFonts w:hint="eastAsia"

                w:ascii="楷体"

                w:hAnsi="楷体"

                w:eastAsia="楷体"

                w:cs="楷体"/>

        <w:sz w:val="20"/>

        <w:szCs w:val="20"/>

        <w:color w:val="${color}"/>

        </w:rPr>

        <w:t>${content}</w:t>

        </w:r>

      </w:p>`

  )

}

如果你还想插入更复杂的格式,则需要根据需要去查看生成好的docx xml模版的代码。

这个我们放到最后来说。

3.插入图片。

插入图片也很简单。模版写法:{%image}

不过官方的图片导出需要收费,所以我们用了一个免费的第三方库。具体写法前面已经给出,这里就不细讲。说一下导出图片需要注意的地方。

你传过去的数据中,图片必须是base64格式的。

关于图片转base64,下面直接上代码:


export function anyGetBase64(url,callback) {

let Img =new Image(),dataURL ='';

  Img.src = url+'?t='+new Date().valueOf(); // 处理缓存,fix缓存bug,有缓存,浏览器会报错;

  Img.setAttribute("crossOrigin", 'Anonymous')// 解决控制台跨域报错的问题

  return new Promise((resolve, reject)=>{

Img.onload =function () {//要先确保图片完整获取到,这是个异步事件

        let canvas =document.createElement("canvas"), //创建canvas元素

            width = Img.width, //确保canvas的尺寸和图片一样

            height = Img.height;

        canvas.width = width;

        canvas.height = height;

        canvas.getContext("2d").drawImage(Img, 0, 0, width, height); //将图片绘制到canvas中

        dataURL = canvas.toDataURL('image/png'); //转换图片为dataURL

// callback ? callback(dataURL) : null; //调用回调函数

        resolve(dataURL)

}

})

}

图片转base64是异步操作,所以使用的时候逻辑处理最好写在finally后面。用法如下:

image

如果你访问的是服务器给的地址,有可能会报跨域的问题,前后端两边都要进行跨域配置。这里就不讲跨域操作了,请自行百度。

4.word导出表格

表格操作还是很常见的,这里讲讲动态导出多行表格。

首先还是先看模版写法,这里的写法和段落循环是一致的:

image

再来看看数据格式:

tfProductArray:[{productName:‘name’}],

具体就是这样。

下面是赠送内容

图文混排(打字有点累了,直接上代码)

我们还是先来看看模版

image

knowledges在最上面是为了去掉段落的空行,空行太多了不好看

因为图片的标签和段落的标签不一致,所以需要把他们分开写。录入数据的时候就不能全部录完段落,最后在录图片,这样的话图片就会在最后,所以需要在段落中依次录入

还是贴一下数据吧。数据就是这个样子。

image

最后说一下如何查看docx格式文件的xml代码

首先将你生成好的模版后缀名改成zip,然后通过解压工具解压,得到的就是一个文件夹

image

打开word,里面有个document.xml的文件,打开文件里面就是xml的代码了。

好了,关于React导出word的知识就讲完了。感谢大家耐心看完,如有问题可私信我,也可以在评论区发布。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值