带中⽂的⽹页下载为PDF格式的⽂件(jsPDF)
1、调研
主要需要⽤到插件jsPDF,jsPDF可以将html下载为pdf格式的⽂件,但⽆法⽀持中⽂字形,下载带中⽂的⽹页会有乱码,经验证可以通过如下3种⽅案下载中⽂⽹页。
2、⽅案
2.1、⽅案⼀(jsPDF + html2canvas):html元素通过html2canvas⽣成canvas,再将canvas 添加到pdf⽂档上。
优点: ⽂档清晰度可控制,下载的PDF⽂件上不会有乱码,html样式还原度100%。
缺点: 分页不好控制,适合不长或者每页内容⽐较规律(⽐如table数据)的页⾯下载。
项⽬下载jsPDF和html2canvas依赖,引⼊依赖,下⾯按不分页与分页的2种情况给出代码⽰例。
2.1.1 不分页
js源码如下:
import { jsPDF } from 'jspdf';
import html2canvas from 'html2canvas';
let element = document.body; //下载整个页⾯,也可以下载页⾯的部分html
let scale = 0.5;
let pageFormat = [element.scrollWidth * scale, element.scrollHeight * scale];
const pdf = new jsPDF({
orientation: 'l',
unit: 'pt', // pdf⼤⼩计量单位
format: pageFormat // ⾃定义第⼀页pdf页⾯⼤⼩,按html元素的⽐例设定
});
let opt = {
scale: 4 // 保证pdf⽂档内容清晰度,放⼤4倍,⽹上说这种⽅案⽂档清晰度不⾼,经验证可以这么解决清晰度问题
};
let width = pageFormat[0];
let height = pageFormat[1];
// 将html元素绘制为cancas
html2canvas(element, opt).then(canvas => {
// cancas添加到pdf⽂档上
pdf.addImage(canvas, 0, 0, width, height);
// 下载
pdf.save('下载' + '.pdf');
});
2.1.2 分页
html:提前规划每⽉pdf内容
<div v-for="(data, index) in pageData" :key="index" :ref="'page' + index" class="pdf-page">
第{{ index + 1 }} 页
......
</div>
js代码:将每⼀块的html转化为canvas,再将canvas添加到pdf的⼀页上
// pageCount: 总共的页数
if (this.pageCount === 0) return;
let elScale = 0.5;
// 将每⼀块的html转化为canvas,再将canvas添加到pdf的⼀页上
let canvasPage = (pdf, index) => {
let element = this.$refs['page' + index][0];
let width = element.scrollWidth * elScale;
let height = element.scrollHeight * elScale;
html2canvas(element, { scale: 4 }).then(canvas => {
html如何下载
(index > 0) && pdf.addPage();
pdf.addImage(canvas, 0, 0, width, height);
if ((index + 1) === this.pageCount) {
pdf.save('demp.pdf');
return;
}
index++;
canvasPage(pdf, index);
});
};
const pdf = new jsPDF({orientation: 'p', unit: 'pt', format: 'a4'});
this.$nextTick(() => {
canvasPage(pdf, 0);
});
}
2.2、⽅案⼆(jsPDF添加ttf中⽂字形⽂件)
优点:pdf⽂档可以⾃动分页。
缺点:需要保证带中⽂的html元素的字体(font-family)和新添加的ttf⽂件字体⼀致,不然中⽂也为乱码,会和你⽤的插件字体有冲突(⽐如你⽤到了iconfont),html中如果有图⽚会⽆法下载成功。
步骤如下:
a、下载ttf⽂件。
c、将font字符串复制粘贴到json⽂件(js⽂件内容很⼤,最好⽤记事本打开会快⼀些),放在前端项⽬的⽂件夹下,通过http 请求json⽂件内容(不直接引⼊js⽂件,因为字体⽂件很⼤,直接引⼊node会报错)。
e、html元素修改字体:。
f、项⽬下载jsPDF和axios依赖(或者其他可以发送请求的插件),引⼊依赖,js源码如下:
import { jsPDF } from 'jspdf';
import axios from 'axios';
<('/jspdf/chinese.json').then(res => {
var callAddFont = function () {
this.addFileToVFS('f', res.data.font);
this.addFont('f', 'chinese', 'normal');
};
jsPDF.API.events.push(['addFonts', callAddFont]);
download(jsPDF);
});
download(jsPDF) {
let element = document.body; //下载整个页⾯,也可以下载页⾯的部分html
let pdf = new jsPDF({
orientation: 'l',
unit: 'pt',
format: 'a4',
compress: true
});
pdf.setFont('chinese');
pdf.setFontSize(14);
let pWidth = pdf.internal.pageSize.width; // 595.28 is the width of a4
let srcWidth = element.scrollWidth;
let margin = 18; // narrow margin - 1.27 cm (36);
let scale = (pWidth - margin * 2) / srcWidth;
pdf.html(element, {
x: margin,
y: margin,
html2canvas: {
scale: scale
},
callback: function (doc) {
doc.save();
}
});
}
2.3、⽅案三(jsPdf + jsPDF-CustomFonts-support)
优点: ⽰例为⾮包管理的项⽬、和⽅案⼆原理差不多,都是替换字体源,引⼊很简单;                  缺点: 对应jsPDF版本⽐较⽼、和jsPdf⽂档的api很多都不⼀致
a、通过script引⼊插件:
<script src="/jspdf/jspdf.es.min.js"></script>
<script src="/jspdf/jspdf.customfonts.min.js"></script>
<script src="/jspdf/default_vfs.js"></script>
b、js代码:
let element = document.body; //下载整个页⾯,也可以下载页⾯的部分html
const doc = new jsPDF({format: 'a4'});
doc.addFont('f', 'NotoSansCJKtc-Regular', 'normal');
doc.setFont('NotoSansCJKtc-Regular');
console.Font());
//最新的jsPdf的api为doc.html()
doc.addHTML(element , {
callback: function (doc) {
doc.save();
},
x: 10,
y: 10,
margin: 10
});
3、总结
1、寻⽅法的过程中淘汰的⽅法:
⽅案三和⽅案⼆的原理差不多,但是不适合通过包管理的项⽬,需要通过script引⼊插件,且对应jsPDF版本⽐较⽼。
2、寻最佳解决⽅案的过程中遇见很多坑,这⾥依然没有完美的解决问题(pdf分页不完美和背景图⽚⽆法下载),后续有突破会继续更新,⼤家在实践过程中如果有问题欢迎留⾔讨论。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。