JS word下載(含兩種方式:html轉(zhuǎn)word莲绰、模板轉(zhuǎn)word)

最近遇到一個(gè)需求-->報(bào)表word下載,網(wǎng)上查了很多資料,發(fā)現(xiàn)其實(shí)無(wú)外乎就兩種吼畏,一種是無(wú)模板html節(jié)點(diǎn)直接轉(zhuǎn)word,一種是固定模板填充值的word,恰好我的業(yè)務(wù)報(bào)表是動(dòng)態(tài)的非固定格式的嘁灯,因此我的處理方式是第一種泻蚊。

類(lèi)型一、html無(wú)模板轉(zhuǎn)word

框架:vue
插件:jquery + file-saver + html-docx-js
邏輯:通過(guò)jquery$('節(jié)點(diǎn)')獲取需要轉(zhuǎn)為word文檔的html節(jié)點(diǎn)丑婿,借助file-saver提供的saveAs方法和html-docx-js提供的asBlob方法轉(zhuǎn)換我們?cè)O(shè)置好的html即可

核心代碼:
import htmlDocx from "html-docx-js/dist/html-docx";
import { saveAs } from "file-saver";
import $ from "jquery";

function exportWord(dom, fileName) {
      setTimeout(() => {
                     let htmlStr = `
                               <!DOCTYPE html>
                               <html lang="en">
                               <body style="font-family:方正仿宋_GBK;mso-ascii-font-family:'Times New Roman'">
                                   ${dom.html()}
                              </body>
                              </html>
                          `;
        saveAs( htmlDocx.asBlob(htmlStr, { orientation: "landscape" }), fileName );
      }, 200);
}

如果你需要轉(zhuǎn)換的html不涉及圖片(包括echarts)性雄,那么上面的轉(zhuǎn)換就已經(jīng)完全可以了,另外fileName的后綴建議使用‘.docx’而不是‘.doc’

如果有圖片(包括echarts)需要轉(zhuǎn)換為word羹奉,我們需要用線上圖片替代本地的圖片秒旋,這樣圖片才能完美兼容Microsoft Office Word和WPC Office兩個(gè)軟件 ,如果不替代的話Microsoft Office Word不兼容尘奏、WPC Office部分版本不兼容滩褥,關(guān)于本地圖片不兼容的問(wèn)題,個(gè)人猜測(cè)是因?yàn)閎ase64 不能完美兼容word軟件炫加,但是二進(jìn)制可以做到完美兼容瑰煎。

線上替代本地圖片具體操作邏輯如下:
第一步:通過(guò)Jquery方法.clone()復(fù)制需要轉(zhuǎn)換為word的html節(jié)點(diǎn) (注意:我們后續(xù)的一系列都是操作的此節(jié)點(diǎn))
第二步:獲取圖片節(jié)點(diǎn),將圖片轉(zhuǎn)換為base64上傳至服務(wù)器 (注意:echarts可直接通過(guò)自帶的方法.getConnectedDataURL({ type: "png" })獲取base64)
第三步:獲取圖片線上地址
第四步:創(chuàng)建節(jié)點(diǎn)<img style="margin:0 auto" width="600" src="'+ 圖片的線上地址 +" />(注意:img的src必須是全路徑K仔ⅰ>频椤! 所以如果接口返回的地址不是全路徑赋铝,需要自行拼接為全路徑)
第五步:通過(guò)jquery方法.html()將第四步創(chuàng)建好的節(jié)點(diǎn)去替換之前第二步獲取到的圖片節(jié)點(diǎn)

至此圖片替換就全部完成了

代碼如下:(下面例中圖片是echarts插勤,如果是img自行百度如何轉(zhuǎn)換base64哦)
import htmlDocx from "html-docx-js/dist/html-docx";
import { saveAs } from "file-saver";
import $ from "jquery";

function exportWord(dom, fileName) {
     setTimeout(async() => {
                   //  1、復(fù)制
                    let DOM=dom.clone();
                   //  2革骨、獲取echarts節(jié)點(diǎn)
                    const echart = DOM.find(".my-echarts");
                    for (let i = 0; i < echart.length; i++) {
                        var curEchart = this.$echarts.getInstanceByDom(echart[i]);
                        if (curEchart) {
                              //獲取base64
                              var base = curEchart.getConnectedDataURL({ type: "png" });
                              //base64轉(zhuǎn)File(這塊需不需要轉(zhuǎn)看項(xiàng)目的后端农尖,因?yàn)槲业暮蠖俗髁松蟼鹘涌诠潭ㄒ?guī)定,只能傳file對(duì)象良哲,所以需要base64轉(zhuǎn)file)
                              var file = this.dataURLtoFile(base, "test.png");
                              console.log(file);
                              //上傳并獲取線上地址
                              let { data } = await apiUploadFormData(file);  //接口上傳 
                              console.log(123123, data);
                             //創(chuàng)建新節(jié)點(diǎn)
                              var _img = $(
                               '<img style="margin:0 auto" width="600" src="' + data.url + '"/>'
                             );  
                            //替換
                           $(echart[i]).html(_img);
                       }
                  }
                    let htmlStr = `
                              <!DOCTYPE html>
                              <html lang="en">
                              <body style="font-family:方正仿宋_GBK;mso-ascii-font-family:'Times New Roman'">
                                  ${DOM.html()}
                             </body>
                             </html>
                         `;
       saveAs( htmlDocx.asBlob(htmlStr, { orientation: "landscape" }), fileName );
     }, 200);
}

//base64轉(zhuǎn)File
function  dataURLtoFile(dataurl, fileName) {
     var arr = dataurl.split(","),
       mime = arr[0].match(/:(.*?);/)[1],
       bstr = atob(arr[1]),
       n = bstr.length,
       u8arr = new Uint8Array(n);
     while (n--) {
       u8arr[n] = bstr.charCodeAt(n);
     }
     return new File([u8arr], fileName, { type: mime });
   },

//圖片上傳接口請(qǐng)求處理(在這里不能使用盛卡,相信每個(gè)小可愛(ài)都看得懂這塊想表達(dá)啥)
import request from '@/utils/request'
export const apiUploadFormData = (file) => {
   let formData = new FormData()
   formData.append("file", file);
   return request.post('圖片上傳接口地址',formData)
}
以上,Html轉(zhuǎn)word就全部完成了

題外話一:關(guān)于word 個(gè)性化樣式

如果想設(shè)置個(gè)性化的樣式筑凫,建議使用jquery方法.find()查找節(jié)點(diǎn)直接添加style屬性.attr('style','樣式')設(shè)置滑沧,即找到需要操作的dom元素,dom添加行內(nèi)樣式即可巍实,注意:添加行內(nèi)樣式時(shí)滓技,需要注意代碼執(zhí)行順序,避免有些行內(nèi)樣式被覆蓋

  // dom是需要轉(zhuǎn)換為word的html節(jié)點(diǎn)
  dom.find('.title').attr('style','font-weight: bold;margin: 10px 0;text-align:center')   

題外話二:關(guān)于word table樣式(按需取用)

我使用的ui庫(kù)是element棚潦,然后我的表格是基于el-table二次封裝好的組件令漂,它在被轉(zhuǎn)換成js原生table表格后,不僅樣式很丑,而且thead和tbody還被識(shí)別成了2個(gè)表格洗显,雖然視覺(jué)上不影響外潜,但是還是存在thead和tbody單元格無(wú)法對(duì)齊的現(xiàn)象

table.png

表格說(shuō)明:我的表格全是后端返回表頭和表格數(shù)據(jù)的動(dòng)態(tài)表格
解決方法:復(fù)制原thead內(nèi)容,插入到tbody成為tbody第一行挠唆,然后刪除thead

        //處理所有表格
        dom.find(".my-global-table").each((key, value) => {
          //處理單個(gè)表格
          //1处窥、獲取表格thead內(nèi)容
          let thArr = [];
          dom
            .find(`.my-global-table:eq(${key}) th div.cell`)
            .each((_key, value) => {
              let m = value.innerHTML;
              let str = `<td><div class="cell">${m}</div></td>`;
              thArr.push(str);
            });
          let thStr = `<tr>${thArr.join("")}</tr>`;
          //2、插入新表頭
          if(thArr.length!==0){
            $(thStr).insertBefore(
              dom.find(`.my-global-table:eq(${key}) tr:eq(1)`)
            );
          }
          //3玄组、刪除舊表頭
          dom
            .find(`.my-global-table:eq(${key}) .el-table__header-wrapper`)
            .remove();
          //4滔驾、如果表格本身有表頭但是無(wú)數(shù)據(jù),我們需要重新添加表頭回去
          let Length = dom.find(`.my-global-table:eq(${key}) tr`).length;
          if (Length == 0 && thArr.length!==0) {
            dom
              .find(`.my-global-table:eq(${key}) tbody`)
              .html(`<tbody>${thStr}</tbody>`);
          }
        });
        console.log(8888, dom);

        //統(tǒng)一設(shè)置所有表格樣式
        dom
          .find(".the-text-table .my-global-table")
          .attr("style", "text-align:center;margin:0 auto;width:80%"); //表格
        dom
          .find(".my-global-table tr")
          .attr(
            "style",
            "height:44px;vertical-align:middle;padding-left:4px;width:80%"
          ); //表格

類(lèi)型二俄讹、固定模板轉(zhuǎn)word

我沒(méi)有實(shí)際操作過(guò)哆致,不過(guò)看下面兩篇參考應(yīng)該足以解決這個(gè)需求吧
參考一
參考二

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市患膛,隨后出現(xiàn)的幾起案子摊阀,更是在濱河造成了極大的恐慌,老刑警劉巖踪蹬,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胞此,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡跃捣,警方通過(guò)查閱死者的電腦和手機(jī)漱牵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)疚漆,“玉大人酣胀,你說(shuō)我怎么就攤上這事∪⑵福” “怎么了闻镶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)丸升。 經(jīng)常有香客問(wèn)我铆农,道長(zhǎng),這世上最難降的妖魔是什么发钝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任顿涣,我火速辦了婚禮波闹,結(jié)果婚禮上酝豪,老公的妹妹穿的比我還像新娘。我一直安慰自己精堕,他們只是感情好孵淘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著歹篓,像睡著了一般瘫证。 火紅的嫁衣襯著肌膚如雪揉阎。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天背捌,我揣著相機(jī)與錄音毙籽,去河邊找鬼。 笑死毡庆,一個(gè)胖子當(dāng)著我的面吹牛坑赡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播么抗,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼毅否,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蝇刀?” 一聲冷哼從身側(cè)響起螟加,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吞琐,沒(méi)想到半個(gè)月后捆探,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡顽分,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年徐许,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卒蘸。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡雌隅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缸沃,到底是詐尸還是另有隱情恰起,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布趾牧,位于F島的核電站检盼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏翘单。R本人自食惡果不足惜吨枉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哄芜。 院中可真熱鬧貌亭,春花似錦、人聲如沸认臊。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至剧腻,卻和暖如春拘央,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背书在。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工灰伟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人儒旬。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓袱箱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親义矛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子发笔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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