1)methods
printingPage() { //pdf下载事件
$store.commit("smartReport/setData", { key: "loading", value: true });//开启loading
let pdfDomTitle = PDFRef.value.querySelector(".title-bd");
let btnsDom = pdfDomTitle.querySelectorAll(".report-btn");//获取需要隐藏的btns
let pdfTitle = pdfDomTitle.querySelector(".title").innerHTML;//获取报表title
btnsDom.forEach((item) => {
item.style.display = "none";
pdfPaging("A4", PDFRef.value); //新增空白元素拼凑分页
html2PDF(PDFRef.value, {
jsPDF: {
unit: "px",
format: "A4",
imageType: "image/jpeg",
success: function (pdf) {
pdfRemoveAllPaging(); //恢复默认:去掉分页,恢复默认布局
btnsDom.forEach((item) => {
item.style.display = "block";
pdf.save(pdfTitle + ".pdf");//下载保存
$store.commit("smartReport/setData", {//隐藏loading
key: "loading",
value: false,
- pdfUtil.js
* pdfUtil.js
* @type: 纸张类型:A4,A3
* @dom:元素
* **/
let pageHeightByType = {
'A4': 29.7,
'A3': 42
//粗略估计 2020 A4纸张在1920屏幕下对应的高度
let pageHeight = 2020; //纸张高度:
let countHeight = 0; //累计高度
let countFunTimes = 0;//记录方法调用次数
//开始分页
export function pdfPaging(type, dom) {
countFunTimes++;
let domH = getCurrentHeight(dom);//当前元素的高度
if (countFunTimes == 1) { //第一次进入该方法:判断纸张大小;是否需要分页
pageHeight = pageHeightByType[type.toUpperCase()];
pageHeight = pageHeight ? pageHeight : 29.7;//默认为A4大小
pageHeight = getPageHeight(pageHeight)
if (pageHeight > domH) {//内容高度未超过一页,不需要分页
countHeight = domH
return;
//内容高度超过一页,需要分页
let children = dom.children;
//getAllChildrenHeight(dom)<=domH 排除行内布局,仅适用于不换行的行内布局
if (children.length > 0 && getAllChildrenHeight(dom) <= (domH + 1)) {
for (let i = 0; i < children.length; i++) {
let child = children[i]
if (child.getAttribute("class") == 'blockDIvId_pdf_self') continue;
let childH = getCurrentHeight(child);
if (childH > pageHeight) {
pdfPaging(1, child)
} else if (pageHeight > childH + countHeight) { //该元素高度childH+未分页元素高度countHeight 小于 页面高度
countHeight += childH;
} else if (child.children.length >= 2) {
pdfPaging(1, child)
} else { //该元素高度childH+未分页元素高度countHeight 超过 页面高度,在该元素之前插入空白div
addChildBefore(child, pageHeight - countHeight);
i++;//添加空白元素后,影响了children数组
countHeight = childH;
} else { //仅一个元素,无法拆分
let divH = domH > pageHeight ? domH % pageHeight : countHeight
addChildBefore(dom, pageHeight - divH);
return
function getCurrentHeight(curNode) {//获取当前元素高度
let childStyle = curNode.currentStyle || window.getComputedStyle(curNode);
let childMarginHeight = parseInt(childStyle.marginTop) + parseInt(childStyle.marginBottom)
let childH = +curNode.offsetHeight + childMarginHeight;
// console.log(childH, childMarginHeight)
return childH
function getPageHeight(pageHeight) { //获取pdf页面高度
let heightUint = 2020 / 29.7;//粗略估计 1910 为 A4纸张在1920屏幕下对应的高度
let widthScale = window.innerWidth; // 当前窗口的宽度
// 尺寸换算
const comparedHeight = widthScale / 1920;
// 通过比例计算高度,
return comparedHeight * heightUint * pageHeight;
function addChildBefore(curNode, height) {//在curNode节点前添加节点
let blockDIv = document.createElement("div");
blockDIv.style.height = height + 'px';
blockDIv.style.background = 'white';
blockDIv.setAttribute('class', 'blockDIvId_pdf_self');
curNode.parentNode.insertBefore(blockDIv, curNode); //在当前元素前面添加
countHeight = 0;
//移除所有分页、参数恢复默认设置
export function pdfRemoveAllPaging() {
let divArr = document.getElementsByClassName("blockDIvId_pdf_self");
for (let i = 0; i < divArr.length; i++) {
let divItem = divArr[i];
divItem.parentNode.removeChild(divItem);
countFunTimes = 0;//恢复默认设置
countHeight = 0;
//判断是否为行内布局,仅适用于不换行的行内布局
function getAllChildrenHeight(dom) {
let children = dom.children;
let h = 0;
for (let i = 0; i < children.length; i++) {
h += getCurrentHeight(children[i]) - 1;//减一是为了避免小数点引起的误差,height会默认向上取整
return h;
【 完 】
【 如有其他方案,欢迎留言或私信交流 】
var domToPdf = require ( 'dom-to-pdf' ) ;
var element = document . getElementById ( 'test' ) ;
var options = {
filename : 'test.pdf'
domToPdf ( element , options , function ( ) {
console . log ( 'done' ) ;
} ) ;
filename字符串,结果PDF文件的名称,默认名称已generated.pdf .pdf
excludeClassNames字符串数组,要从PDF中排除的元素的类名称列
/* eslint-disable */
const Print = function (dom, options) {
if (!(this instanceof Print)) return new Print(dom, options);
this.options = this.extend({
'noPrint': '.no-print'
}, options);
if ((typeof dom) === string) {
this.dom = document.querySelector(dom);
} else
jspdf分页有个比较不好的地方就内容过长的时候虽然会虽然能做到分页,但是会把内容给截断,解决思路是给每个可能会被截断元素加上类,然后动态的计算该元素的位置是否在下一页和上一页之间,如果在的话就添加一个空白元素把这个元素给挤下去,这样就能实现了
......
vue.js+jspdf.js+html2pdf.js 实现页面导出PDF
原本是导出word但客户考虑到问到的安全性要求改成了PDF,由于之前的word导出也是有前端生成的,所以为了不增加工作量导出依旧有前端完成。起初在网上找了很多方法都无法实现,都想放弃了让后端写,后来看到了关于jspdf.js+html2canvas.js的文章,想着试试看吧。对于前端导出PDF我就是个小白,啥也不会。按着文章一步步写吧。
安装插件html2canvas和jspdf
npm install html2canvas--s
jspdf-html2canvas 网页导出pdf 自动根据dom子节点的高度进行分页,避免dom的内容在分页的时候被截断说明直接上代码
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
要导出的内容用 .pdf 包裹 ,默认会以.pdf的子节点进行整块的高度计算,如果孙节点需要整块计算,孙节点的父节点上增加.pdf;
如果导出的内容里面有外部图片引用,需要配置外部图片支持跨域;
增加了 图片拖拽 功能,你可
/ 获得该容器到文档顶部的距离。//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高。//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)// 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此。// 获得滚动条长度的一半。// 获得该容器的高。// 获得该容器的宽。//一页pdf显示html页面生成的canvas高度;//未生成pdf的html页面高度。
* @param html { String } DOM树
* @param isOne { Boolean } 是否为单页 默认 否(false)
* @return 文件 {pdf格式}
'use strict'
import * as jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
export default async (html, isOne) => {