相关文章推荐
坏坏的保温杯  ·  从根本上解决npm ...·  1 周前    · 
大鼻子的海龟  ·  Axios ...·  11 月前    · 
粗眉毛的镜子  ·  Java 8 ...·  1 年前    · 
单身的麦片  ·  [Error] cannot pass ...·  1 年前    · 

由前端实现的报表(含echarts图和table表格),需要将整个报表进行导出下载,但不包括页面中的导航栏及其他元素。

1)在导出pdf时 ,如果页面长度超过一页,插件无法只能识别分页,会将内容切割,如下所示:
在这里插入图片描述
2)目的:实现当前页放不下该页面元素时,插入空白元素将该元素下挤,实现分页但不分割内容

3、解决方案

通过计算dom元素的高度逐一拆分,动态增加dom元素使布局满足分页但不分割内容,效果如下:
在这里插入图片描述
注意:
1)计算高度时,切莫忘记margin;
2)由于通过dom.children 获取子元素,逐一累计并拆分,在添加空白元素节点后,获取的子集也会增加,注意循环中的计数单位自增,对空白元素做标记,如果进入到循环则排除;
3)由于本案例中是将页面元素直接做的变化,再pdf下载后,需移除所有增加的空白元素,恢复页面布局;
4)html2PDF插件中的dom元素参数,只能传页面中有的元素,如若隐藏或深度克隆但未添加到html中的元素,则识别不到,控制台会报错(隐藏了的元素也无法导出);
5)如果将克隆的元素添加到页面中,会丢失echarts图表,故此方案的操作对象为要导出的原dom对象;
6)若页面中的有重叠的元素,会影响高度的计算,修改getCurrentHeight即可;

4、代码如下:

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,
  1. 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高度;//未生成pdfhtml页面高度。 * @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) => {