使用html2canvas+pdfmake
先使用html2canvas将网页转化成canvas对象,从canvas中生成图像数据,再利用pdfmake将其转成pdf进行打印
这种方法具有普适性,不用管dom节点的具体内容。主要解决了分页和自定义页眉页脚的问题,通过pdfmake也可以自定义很多文档属性等内容。
遗留的主要问题是分页时会出现同一个字或图片变成两半的问题
另外在我的项目中使用pdfmake需要手动去替换node_modules目录下的vfs_fonts文件来显示中文或更换字体(我将vfs_fonts.js手动拷贝到项目中并引入时会报错,vfs_fonts.js代码里的this为undefined,目前尚未找到原因和好的解决方案),而在原生js中则没有这个问题,目前还不清楚原因。
对于html打印,目前提供的解决思路如下:
1、 先将获取到的dom节点进行缩放(使用transform),使其适应于打印纸张的尺寸,然后使用table,利用thead和tfoot可以在每页显示的特征来作为页眉和页脚。 目前我还未找到一个显示页码的方式(页眉页脚是固定的),以及没有较好的排班方式,该方式是可以较好的进行分页的。
2、 确定页面尺寸,在每页放置head,main和foot三个部分,即页眉页脚和打印主体内容,针对打印主体设置margin-top,使其出现分页的显示效果。 该方法可行,但也会出现分页不合理的问题
3、使用html2canvas+jspdf,该方法网上有教程,显示页眉页脚的时候也类似于方法2,需要手动控制尺寸,生成页眉和页脚的html代码,
4、使用html2canvas+pdfmake,该方法可以方便的设置页眉页脚,和3的区别不大,但目前pdfmake好像不支持页眉和页脚设置成图片。
5、(只是个想法)遍历节点,手动进行分页等操作(在合适的位置插入页眉和页脚,针对不同的标签情况进行分页),如果想用这种方法去实现普适性的打印的话,过于复杂。
chrome原生打印存在的主要问题就是很多东西都没办法自定义(ie等浏览器也是,各浏览器情况不同,也分轻重)
无法较为复杂的打印需求。目前的解决方法还不完善,对比1~4四种方法,4的表现最好,代码也最简洁。
代码如下(在react项目里, 主要方法是cutImg和print):
/**
* Created by Siver on 2018/7/11.
* ReactDomPrinter节点转化为pdf进行打印
*/
import React from 'react'
import PropTypes from 'prop-types'
import html2canvas from 'html2canvas'
import pdfMake from 'pdfmake/build/pdfmake'
import pdfFonts from 'pdfmake/build/vfs_fonts'
export default class ReactDomPrinter extends React.Component {
static propTypes = {
/** Dom'id to print */
domID: PropTypes.string.isRequired,
pageHeight: PropTypes.number,
pageWidth: PropTypes.number,
margin: PropTypes.shape({
left: PropTypes.number,
top: PropTypes.number,
right: PropTypes.number,
bottom: PropTypes.number,
}),
header: PropTypes.oneOfType([
PropTypes.object,
PropTypes.func,
]),
footer: PropTypes.oneOfType([
PropTypes.object,
PropTypes.func,
]),
pageSize: PropTypes.string,
};
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
static defaultProps = {
pageHeight: 841.89,
pageWidth: 595.28,
margin: {
left: 20,
top: 30,
right: 20,
bottom: 30
},
header: {
columns: [
{text: 'begin', alignment: 'left', margin: 5},
{text: 'end', alignment: 'right', margin: 5}
]
},
footer: (currentPage, pageCount) => {
return {
text: currentPage.toString() + '/' + pageCount,
alignment: 'center',
margin: 5
};
},
pageSize: 'A4'
};
constructor(props) {
super(props);
pdfMake.vfs = pdfFonts.pdfMake.vfs;
this.state = {
domID: this.props.domID
}
}
componentWillReceiveProps(next) {
if (next.domID !== this.props.domID) {
this.setState({
domID: next.domID
});
}
}
print = () => {
let dom = document.getElementById(this.state.domID);
html2canvas(dom).then(canvas => {
const PAGE_H = this.props.pageHeight;
const PAGE_W = this.props.pageWidth;
const margin = this.props.margin;
let IMG_W = PAGE_W - margin.left - margin.right;
let IMG_H = PAGE_H - margin.top - margin.bottom;
let pageData = canvas.toDataURL('image/jpeg', 1.0);
let docDefinition = {
pageSize: this.props.pageSize,
footer: this.props.footer,
header: this.props.header,
pageMargins: [margin.left, margin.top, margin.right, margin.bottom],
};
//每页显示的实际图片高度;
let pageHeight = canvas.width / IMG_W * IMG_H;
//页面偏移
let top = 0;
//content
let content = [];
//当内容未超过pdf一页显示的范围,无需分页
if (canvas.height < pageHeight) {
content.push({
image: pageData,
margin: [0, 0],
width: IMG_W,
height: canvas.height * IMG_W / canvas.width
});
} else {
while (top < canvas.height) {
let cutHeight = top + pageHeight > canvas.height ? canvas.height - top : pageHeight;
let obj = {
image: this.cutImg(canvas, cutHeight, canvas.width, top, 0),
margin: [0, 0],
width: IMG_W,
height: cutHeight * IMG_W / canvas.width,
};
top += pageHeight;
//分页
if (top < canvas.height) obj.pageBreak = 'after';
content.push(obj);
}
}
docDefinition.content = content;
pdfMake.createPdf(docDefinition).open();
});
};
//canvas对图片进行裁剪
cutImg = (imgData, height, width, top, left) => {
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(imgData, left, top, width, height, 0, 0, width, height);
// 保存图片信息
return canvas.toDataURL('image/jpeg', 1.0);
};
render() {
return (
<button onClick={this.print}>打印</button>
)
}
}