pdfMake前端導(dǎo)出pdf

pdfMake前端導(dǎo)出pdf

目前導(dǎo)出PDF還是后端(或nodejs)比較好. (如果沒(méi)有必要)

導(dǎo)出方案

后端: IText,wkhtmltopdf...等等.

前端: jsPdf,pdfKit,react-pdf...等等.

現(xiàn)在網(wǎng)上一提到前端導(dǎo)出pdf的絕大多數(shù)都是html2canvas + jspdf 實(shí)現(xiàn)html轉(zhuǎn)pdf.這是非常棒的一個(gè)解決方案,不過(guò)它有一個(gè)弊端就是內(nèi)容放大之后會(huì)失真.如果遇到這類(lèi)需求就只能含淚放棄了.html2canvas主要解決的是jspdf中文亂碼的問(wèn)題,因?yàn)槭峭鈬?guó)小哥開(kāi)發(fā)的,所以就沒(méi)考慮過(guò)中文兼容.這些或多或少的pdf框架都有中文亂碼的問(wèn)題.

還有一種是pdfKit的二次封裝 pdfMake .這也是我所采用的方案,相比較jspdf和pdfkit,使用起來(lái)更易上手.也有中文亂碼的解決方案.github地址 官方網(wǎng)站

使用pdfMake

這里我又用到了webWorker,具體原因和配置我后面解釋.

// UI線程--------------------------------------------
import Worker from './components/imppdf.worker.js';
let worker = new Worker(); // 傳入 worker 腳本文件的路徑即可
const dd = {
    content: [
        '中英文測(cè)試',
        'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
    ],
    defaultStyle: {
        font: '方正姚體'
    }
};
worker.postMessage(dd);
worker.onmessage = function (event: any) {
  if (event.data?.type === "progress") {
    // 返回的進(jìn)度信息0-1
  } else {
    const link = document.createElement("a");
    link.style.display = "none";
    link.href = URL.createObjectURL(event.data);
    link.setAttribute("download", decodeURI('下載.pdf'));
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  };
}

// webWorker-----------------------------------------
import pdfMake from "pdfmake/build/pdfmake"; 
import FZvfs from "./FZYTvfs_fonts"; // .ttf字體文件打包后的js文件
pdfMake.vfs = FZvfs;
pdfMake.fonts = { // 添加字體庫(kù)
  方正姚體: {
    normal: 'FZYTK.TTF',
    bold: 'FZYTK.TTF',
    italics: 'FZYTK.TTF',
    bolditalics: 'FZYTK.TTF',
  }
};
onmessage = function ({ data }) {
  // 工作線程收到主線程的消息
  if(!data) return;
  let pdf = pdfMake.createPdf(data);
  pdf.getBlob((blob) => {
    postMessage(blob)
  }, { progressCallback(num) { postMessage({ type:'progress',num})}});
};

使用中的問(wèn)題

雖然支持svg,但是svg如果很大它無(wú)法配置跨頁(yè)φ(* ̄0 ̄)

這個(gè)問(wèn)題很重要,因?yàn)槲矣胑charts生成的svg圖片,無(wú)法通過(guò)fit屬性壓縮大小(長(zhǎng)寬).所以考慮手動(dòng)切割圖片,但因?yàn)閷?duì)svg的了解不深所以放棄了.后面采用position定位屬性手動(dòng)偏移和計(jì)算,在通過(guò)pagebreak配置分頁(yè).實(shí)現(xiàn)跨頁(yè)效果
下貼手動(dòng)偏移的代碼

interface SvgProps {
  src: string;
  wh: number[]; // [寬,高]
}

const getSvgContents = (svg: SvgProps) => {
  if (!svg) return null;
  let { src, wh } = svg;
  let [width, height] = wh;
  let rw = pageWidth - pageMargins[0] - pageMargins[2];
  let ratio = rw / width;
  let rH = height * ratio;
  let spliteNum = Math.ceil(height / pageHeight); 
  let content = [];
  for (let i = 0; i < spliteNum; i++) {
    content.push({ svg: src, margin: [0, 0, 0, 0], fit: [rw, rH], absolutePosition: { x: 0, y: i && -1 * i * pageHeight }, pageBreak: 'before', preserveLeadingSpaces: true },)
  }
  return content
}

問(wèn)題解決了,但是這就導(dǎo)致生成pdf的時(shí)間變得更長(zhǎng)了 o( ̄▽?zhuān)?/em>)o

渲染中會(huì)阻塞線程

通過(guò)回調(diào)本應(yīng)該拿到進(jìn)度并繪制在進(jìn)度條上給用戶了解,但是因?yàn)樗膱?zhí)行是同步代碼,所以會(huì)優(yōu)于頁(yè)面渲染.同時(shí)頁(yè)面也是阻塞狀態(tài),無(wú)法操作.這個(gè)很難受,想了一下就用webWorker來(lái)生成吧.使用中要注意配置<img src="https://webpack.docschina.org/d19378a95ebe6b15d5ddea281138dcf4.svg" width = "20" height = "20" alt="圖片名稱(chēng)" align=center />webpack,官方配置鏈接很簡(jiǎn)單.我使用的是 chainWebpack,下面就貼一下代碼吧.

 chainWebpack(config) {
    config.module.rule()
      .test(/\.worker\.js$/)
      .use('worker-loader')
      .loader('worker-loader')
      .end()
  },

生成時(shí)間很長(zhǎng),相對(duì)chrome打印而言

我這是頁(yè)數(shù)*1秒,給了一個(gè)進(jìn)度條讓用戶感覺(jué)在工作,盡量減少不適感.

中文亂碼(配置個(gè)字體)

配置字體就行,不同的字體可以自己生成.我用的一個(gè)現(xiàn)成的,地址:https://files.cnblogs.com/files/s313139232/方正姚體vfs_fonts.js

打包教程:http://www.cnblogs.com/xrab/p/7210588.html

打包步驟:

1.在https://github.com/bpampuch/pdfmake下載pdfmake的源文件

2.在根目錄用 npm 安裝 gulp

npm install gulp --save-dev

3.安裝pdfmake依賴(lài)包

npm install

4.在cmd運(yùn)行打包examples/fonts中的.ttf文件的命令。

gulp buildFonts

5.然后在 build 文件中可以找到vfs_fonts.js文件。

由于字體打包文件較大,建議examples/fonts中的.ttf文件只放置一個(gè)字體文件。

結(jié)語(yǔ)

使用起來(lái)非常的人性化,很棒哈.但是最好還是后端借助工具導(dǎo)出,控制更給力,性能更好,前端處理還是有很多不適.

大家有什么問(wèn)題或者建議可以留言討論哈 ( ?? ω ?? )?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容