我們一起探索前端生成PDF
巧用pdfmake。
在使用層面講如何使用pdfmake生成現(xiàn)有報(bào)告,從以下幾方面實(shí)現(xiàn):
- 支持中文
- 預(yù)覽頁面搭建
- 封面實(shí)現(xiàn)和斷頁
- 頁眉和頁腳實(shí)現(xiàn)
- pdfmake顯示類型
- 如何實(shí)現(xiàn)內(nèi)邊距
- table無法居中顯示
支持中文
pdfmake默認(rèn)不支持中文,需要我們自己實(shí)現(xiàn)。找中文的字體文件(ttf結(jié)尾的文件)這個(gè)任務(wù)就交到我們自己手里了,并且字體文件需要支持粗體和斜體,否則字體加粗和斜體屬性不生效。
把我們找到的字體文件,放入pdfmake官方github目錄下examples下,執(zhí)行
- npm run build:vfs
它會(huì)把你放入examples下的所有字體都統(tǒng)一打包到build文件下的vfs_fonts.js中,然后在項(xiàng)目中使用:
- import pdfmake from "pdfmake/build/pdfmake"
- const pdfFonts = require('@/assets/js/vfs_fonts.js')
- pdfMake.vfs = pdfFonts
- pdfMake.fonts = {
- Roboto: {
- normal: 'Roboto-Regular.ttf',
- bold: 'Roboto-Medium.ttf',
- italics: 'Roboto-Italic.ttf',
- bolditalics: 'Roboto-Italic.ttf'
- },
- 微軟雅黑: {
- normal: '微軟雅黑.ttf',
- bold: '微軟雅黑-bold.ttf',
- italics: '微軟雅黑-italics.ttf',
- bolditalics: '微軟雅黑-bolditalics.ttf'
- }
- }
使用時(shí):
- var docDefinition = {
- content: [ '驚天碼盜' ],
- defaultStyle: {
- fontSize: 15,
- bold: true,
- font:"微軟雅黑"
- }
- };
預(yù)覽頁面搭建
pdf預(yù)覽的邏輯大都是通過iframe實(shí)現(xiàn),通過getDataUrl獲取url地址
- import pdfmake from "pdfmake/build/pdfmake"
- export function previewPdf(params) {
- if(!params) return ;
- const pdfDocGenerator = pdfMake.createPdf(params);
- pdfDocGenerator.getDataUrl( dataUrl=>{
- const targetElement = document.querySelector("#iframeContainer");
- const pdfMakeIframe = document.querySelector("#pdfMakeKey");
- if(pdfMakeIframe){
- pdfMakeIframe.src = dataUrl;
- }else{
- const iframe = document.createElement("iframe");
- iframe.id = 'pdfMakeKey';
- iframe.src = dataUrl;
- targetElement.appendChild(iframe)
- }
- }}
封面實(shí)現(xiàn)和斷頁
pdfmake默認(rèn)是沒有封面這個(gè)設(shè)置,但是提供了一個(gè)設(shè)置背景的函數(shù),可以給每個(gè)頁面設(shè)置一個(gè)背景,可以是文字背景,也可以是圖片背景。
- const docDefinition = {
- background: function( currentPage, pageSize){
- if(currentPage === 1){
- return {
- iamge: "bgCoverImgUrl",
- width: pageSize.width,
- height: pageSize.height
- }
- }
- return null;
- }
- content: ["驚天碼盜"]
- }
這個(gè)自動(dòng)斷頁可以說是非常的贊,省去了你復(fù)雜的計(jì)算。如果你想某一頁單獨(dú)放一段文案,或者在某段文案后單獨(dú)開一頁,pageBreak可以幫你實(shí)現(xiàn)。
- {
- pageOrientation: 'portrait',
- content: [
- {text: 'Text on Portrait'},
- {text: 'Text on Landscape', pageOrientation: 'landscape', pageBreak: 'before'},
- {text: 'Text on Landscape 2', pageOrientation: 'portrait', pageBreak: 'after'},
- {text: 'Text on Portrait 2'},
- ]
- }
頁眉和頁腳
頁眉和頁腳的實(shí)現(xiàn)就太方便了。
- const docDefinition = {
- footer: function(currentPage, pageCount) {
- return currentPage.toString() + ' of ' + pageCount;
- },
- header: function(currentPage, pageCount, pageSize) {
- return [{
- columns: [
- {
- text: this.headerContent.left,
- alignment: 'left'
- },
- {
- text: this.headerContent.middle,
- alignment: 'center'
- },
- {
- text: this.headerContent.right,
- alignment: 'right'
- }
- ],
- margin: [10, 20]
- }]
- },
- content: ["驚天碼盜"]
- };
可以精準(zhǔn)定位某個(gè)頁面做一些特殊的設(shè)置。
顯示類型
相對(duì)于前端來說大多顯示類型都已經(jīng)定型了,比如表格、文本、列表、圖片等。在pdfmake中一共給我們提供了這些顯示類型:
text |
普通文本,需要注意的就是字體,如果所提供字體不支持,所設(shè)置的屬性就不顯示。同時(shí)text可以嵌套。 |
columns |
列,平鋪的列元素。在pdfmake中沒有塊級(jí)元素的概念,如果你想平鋪兩個(gè)或者多個(gè)文本(比如前面icon,后面文本),colums會(huì)滿足你。每列之間的距離可以通過columnGap設(shè)置。 |
list |
跟html標(biāo)簽ul或ol相同。 |
table |
表格,唯一提供內(nèi)邊距屬性的類型。強(qiáng)大到可以實(shí)現(xiàn)任何簡單的樣式,相當(dāng)于display:table。但是弊端也相當(dāng)明顯,不能垂直居中。 |
image/svg |
圖片。 |
stack | 棧,相當(dāng)于數(shù)組[]。 |
內(nèi)邊距的實(shí)現(xiàn)
text文本在pdfmake中是一個(gè)塊級(jí)元素(css思路定義)。無法實(shí)現(xiàn)內(nèi)邊距,單個(gè)text文本獨(dú)占一行。
- const dd = {
- content: [
- 'First paragraph',
- { text:"234", background:'red',color:"#fff",fontSize:20 },
- 'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
- ]
- }
在pdfmake類型中只有table可以實(shí)現(xiàn)內(nèi)邊距,那么我們就可以嘗試以table的方式布局,例如
- const dd = {
- content: [
- {
- margin: [0, 20],
- table: {
- body: [
- [
- { text: 'CONTENTS', width: 'auto', fillColor: '#e7e6e6', fontSize: 26 },
- { text: 'Padding ', fillColor: '#58ac5b', color: '#FFF', fontSize: 26 }
- ]
- ]
- },
- layout: {
- defaultBorder: false,
- paddingLeft: function (i, node) {
- if (i === 0) {
- return 10
- }
- return 20
- },
- paddingRight: function (i, node) {
- if (i === 0) {
- return 10
- }
- return 20
- },
- paddingTop: function (i, node) { return 10 },
- paddingBottom: function (i, node) { return 10 }
- }
- }
- ]
- }
效果是:
像目錄這種效果也是table做出來的:
table的缺陷
看似table可以實(shí)現(xiàn)任何樣本組合,但是在單元格垂直居中這塊,卡住了。
- {
- // style: 'tableExample',
- table: {
- body: [
- ['Column 1', 'Column 2The following table has nothing more than a body array,The following table has nothing more than a body array,The following table has nothing more than a body array,The following table has nothing more than a body array', 'Column 3'],
- ['One value goes here', 'Another one here', 'OK?']
- ]
- }
- }
其他
目前發(fā)現(xiàn)不完美的一點(diǎn),就是table單元格垂直居中,除了這一點(diǎn),table很靈活,可以實(shí)現(xiàn)多級(jí)表頭,嵌套表格,合并單元格,靈活定制各個(gè)單元格邊框線條寬度和顏色。
同時(shí)還具備水印、加密、二維碼生成、內(nèi)外鏈接、目錄生成。相比jspdf幫我們節(jié)省了很多步驟。那么我們下期聊聊jsPdf。
本文轉(zhuǎn)載自微信公眾號(hào)「驚天碼盜」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系驚天碼盜公眾號(hào)。