一、技术选型
1.html转换成canvas后生成图片导出pdf(本文选用)
- html转canvas插件:html2canvas是一款将HTML代码转换成Canvas的插件;
- canvas生成pdf:jsPDF是一个使用Javascript语言生成PDF的开源库
2.HTML代码转出pdf
wkhtmltopdf是一款将HTML代码转换成pdf的插件,表格场景使用居多
二、技术实现(基于html2canvas和jsPDF实现)
1.安装插件
npm i html2canvas -S
npm i jspdf -S
2.注册及实现封装
以下封装的代码可以直接引用到项目文件中使用,需要注意以下几点:
- 由于需要固定导出pdf图片大小,所以需要给导出的dom上添加.pdf-screen样式类用于查找导出元素,然后更改导出元素样式;
- 导出页面尺寸固定为a4大小;
/**
* @file 导出pdf文件
*/
import html2canvas from 'html2canvas';
import JsPDF from 'jspdf';
/* eslint-disable */
const PDF = {};
// a4
let a4Width = 595.28;
let a4Height = 841.89;
let defaultOptions = {
name: new Date().getTime(),
scale: window.devicePixelRatio * 2,
padding: 0,
width: 595.28 * 2,
allowTaint: true,
onclone: function (dom) {
let screen = dom.querySelector('.pdf-screen');
screen.style.width = 595.28 * 2 + 'px';
screen.style.padding = '10px';
}
}
PDF.install = function (Vue, rootOptions = {}) {
Vue.prototype.$pdf = function (dom, options = rootOptions) {
options = Object.assign(defaultOptions, options);
html2canvas(dom, options).then(canvas => {
let position = 0;
// 生成的画布元素宽高(需要收缩回原比例大小)
let canvasWidth = canvas.width / options.scale;
let canvasHeight = canvas.height / options.scale;
// 页面等比例缩放后宽高
let pageWidth = a4Width;
let pageHeight = (a4Width / canvasWidth) * canvasHeight;
//返回图片dataURL,参数:图片格式和清晰度(0-1)
let jpeg = canvas.toDataURL('image/jpeg', 1.0);
//方向默认竖直,尺寸ponits,格式a4[595.28,841.89]
let doc = new JsPDF('', 'pt', 'a4');
//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
//当内容未超过pdf一页显示的范围,无需分页
if (canvasHeight < pageHeight) {
doc.addImage(jpeg, 'JPEG', 0, 0, pageWidth, pageHeight); // 从图片顶部开始打印
} else {
while (canvasHeight > 0) {
doc.addImage(jpeg, 'JPEG', 0, position, pageWidth, pageHeight);
canvasHeight -= pageHeight;
position -= a4Height;
//避免添加空白页
if (canvasHeight > 0) {
doc.addPage();
}
}
}
doc.save(options.name + '.pdf');
});
};
};
export default PDF;
3.使用方式
// 在 main.js 中导入插件
import pdf from "./plugins/pdf";
// 注册插件
Vue.use(PDF);
// 在需要导出pdf的函数中调用
// dom是需要导出的最外层元素
this.$pdf(dom, options);
// 使用案例(该配置可参考HTML2CANVAS相关配置)
this.$pdf(this.$refs.screen, {
name: 'filename', // 导出文件名
scale: 2, // 导出文件清晰度,值越大清晰度越高,文件体积越大(默认值为设备dpr*2)
ignoreElements: (element) => { // 忽略渲染元素(通过查询dom元素,不局限于类名查询)
if (element.className.indexOf('className') !== -1) {
return true;
}
}
});
三、遇到问题及解决方案
1. pdf内容截断问题 (待解决)
问题描述:由于实现原理是将html转换成canvas后生成图片的形式导出pdf文件,会导致canvas生成的长图在分页保存的过程中出现内容被截断的情况;
2. PDF导出文件分辨率问题(已解决)
问题描述:canvas生成的图片分辨率过低;
解决方案:可对dom元素按比例进行缩放后,再生成图片并导出到pdf文件中;
四、待优化点
1.导出时附带水印效果
五、参考资料