React前端實(shí)現(xiàn)word導(dǎo)出(word表格操作,圖片操作舰蟆,字體顏色修改)

前言

本文使用前端框架React趣惠。
最近項(xiàng)目遇到一個需求狸棍,需要前端去導(dǎo)出word。百度了一圈后信卡,找到了一個導(dǎo)出word的模版庫隔缀,非常好用。
貼上地址:docxtemplater
借鑒了大佬的圖片導(dǎo)出寫法傍菇,下面貼上地址:
Word導(dǎo)出圖片

功能點(diǎn)

1.導(dǎo)出指定排版的文章
2.導(dǎo)出帶樣式的文字
3.導(dǎo)出圖片
4.導(dǎo)出表格

使用方法

首先講一下在代碼中怎么使用
首先導(dǎo)入第三方庫:

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

直接上代碼(可直接復(fù)制):


/**

*函數(shù)傳入?yún)?shù)說明:filepath:word保存的地址猾瘸,

*wordData:word導(dǎo)出需要的數(shù)據(jù),

*outPath:word導(dǎo)出文件名

* */

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

// 讀取并獲得模板文件的二進(jìn)制內(nèi)容丢习,是docxtemplater提供的固定寫法

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

// exportTemplate.docx是模板牵触,React寫在public里。我們在導(dǎo)出的時候咐低,會根據(jù)此模板來導(dǎo)出對應(yīng)的數(shù)據(jù)

//圖片導(dǎo)出功能

      let opts = {

        centered:false,

        fileType:"docx",

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

                let width =100;

                let height =100;

                return [width,height];

        },

        getImage:(tagValue)=>{

            / /圖片base64轉(zhuǎn)字節(jié)數(shù)組

            return base64DataURLToArrayBuffer(tagValue)

        }

  }

let imageModule = new ImageModule(opts);

      // 創(chuàng)建一個PizZip實(shí)例揽思,內(nèi)容為模板的內(nèi)容

      let zip =new PizZip(content);

      // 創(chuàng)建并加載docxtemplater實(shí)例對象

      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文件(不是一個真實(shí)的文件,而是在內(nèi)存中的表示)

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

        type : "blob",

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

     });

     //Output the document using Data-URI

      saveAs(out, outPath);

  })

}

//圖片轉(zhuǎn)base64字節(jié)碼

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文件夾下钉汗。如果你的項(xiàng)目沒有public文件夾。

1.重新創(chuàng)建項(xiàng)目

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

image

然后你需要在打包文件中指定word文件上傳后讀取的位置鲤屡,不然打包發(fā)布后服務(wù)器讀取不到文件

具體操作如下:

我的打包文件:

image

導(dǎo)入一個第三方庫: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操作已經(jīng)講完了损痰,下面輪到word模版和數(shù)據(jù)處理了。

首先wordData傳遞的數(shù)據(jù)是object鍵值對類型的數(shù)據(jù)酒来。具體可看官方文檔docxtemplater

1.排版

如果你需要插入固定格式的文字卢未,例如下面這種

image

第一種模版寫法為:

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

數(shù)據(jù)格式:products:[{title:'name'}]

第二種模版寫法:

{#products}{.}{/products}

數(shù)據(jù)格式:products:[‘name’]

具體使用那種看你的數(shù)據(jù)格式

2.帶格式的文本

image

如這種正數(shù)為紅色,負(fù)數(shù)為綠色堰汉。

需要插入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>`

  )

}

如果你還想插入更復(fù)雜的格式翘鸭,則需要根據(jù)需要去查看生成好的docx xml模版的代碼滴铅。

這個我們放到最后來說。

3.插入圖片就乓。

插入圖片也很簡單失息。模版寫法:{%image}

不過官方的圖片導(dǎo)出需要收費(fèi),所以我們用了一個免費(fèi)的第三方庫档址。具體寫法前面已經(jīng)給出盹兢,這里就不細(xì)講。說一下導(dǎo)出圖片需要注意的地方守伸。

你傳過去的數(shù)據(jù)中绎秒,圖片必須是base64格式的。

關(guān)于圖片轉(zhuǎn)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"), //創(chuàng)建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'); //轉(zhuǎn)換圖片為dataURL

// callback ? callback(dataURL) : null; //調(diào)用回調(diào)函數(shù)

        resolve(dataURL)

}

})

}

圖片轉(zhuǎn)base64是異步操作,所以使用的時候邏輯處理最好寫在finally后面玄呛。用法如下:

image

如果你訪問的是服務(wù)器給的地址阅懦,有可能會報跨域的問題,前后端兩邊都要進(jìn)行跨域配置徘铝。這里就不講跨域操作了耳胎,請自行百度。

4.word導(dǎo)出表格

表格操作還是很常見的惕它,這里講講動態(tài)導(dǎo)出多行表格怕午。

首先還是先看模版寫法,這里的寫法和段落循環(huán)是一致的:

image

再來看看數(shù)據(jù)格式:

tfProductArray:[{productName:'name'}],

具體就是這樣。

下面是贈送內(nèi)容

圖文混排(打字有點(diǎn)累了淹魄,直接上代碼)

我們還是先來看看模版

image

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

因?yàn)閳D片的標(biāo)簽和段落的標(biāo)簽不一致,所以需要把他們分開寫甲锡。錄入數(shù)據(jù)的時候就不能全部錄完段落兆蕉,最后在錄圖片,這樣的話圖片就會在最后缤沦,所以需要在段落中依次錄入

還是貼一下數(shù)據(jù)吧虎韵。數(shù)據(jù)就是這個樣子。

image

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

首先將你生成好的模版后綴名改成zip疚俱,然后通過解壓工具解壓劝术,得到的就是一個文件夾

image

打開word缩多,里面有個document.xml的文件呆奕,打開文件里面就是xml的代碼了。

好了衬吆,關(guān)于React導(dǎo)出word的知識就講完了梁钾。感謝大家耐心看完,如有問題可私信我逊抡,也可以在評論區(qū)發(fā)布姆泻。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市冒嫡,隨后出現(xiàn)的幾起案子拇勃,更是在濱河造成了極大的恐慌,老刑警劉巖孝凌,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件方咆,死亡現(xiàn)場離奇詭異,居然都是意外死亡蟀架,警方通過查閱死者的電腦和手機(jī)瓣赂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門榆骚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人煌集,你說我怎么就攤上這事妓肢。” “怎么了苫纤?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵碉钠,是天一觀的道長。 經(jīng)常有香客問我方面,道長放钦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任恭金,我火速辦了婚禮操禀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘横腿。我一直安慰自己颓屑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布耿焊。 她就那樣靜靜地躺著揪惦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪罗侯。 梳的紋絲不亂的頭發(fā)上器腋,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機(jī)與錄音钩杰,去河邊找鬼纫塌。 笑死,一個胖子當(dāng)著我的面吹牛讲弄,可吹牛的內(nèi)容都是我干的措左。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼避除,長吁一口氣:“原來是場噩夢啊……” “哼怎披!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瓶摆,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤凉逛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后群井,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體状飞,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了昔瞧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片指蚁。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖自晰,靈堂內(nèi)的尸體忽然破棺而出凝化,到底是詐尸還是另有隱情,我是刑警寧澤酬荞,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布搓劫,位于F島的核電站,受9級特大地震影響混巧,放射性物質(zhì)發(fā)生泄漏枪向。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一咧党、第九天 我趴在偏房一處隱蔽的房頂上張望秘蛔。 院中可真熱鬧,春花似錦傍衡、人聲如沸深员。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽倦畅。三九已至,卻和暖如春绣的,著一層夾襖步出監(jiān)牢的瞬間叠赐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工屡江, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芭概,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓盼理,卻偏偏與公主長得像谈山,于是被迫代替她去往敵國和親俄删。 傳聞我的和親對象是個殘疾皇子宏怔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容