需求:我有一个页面,是由多个模块组成的,现在我需要把页面转为pdf并下载,但是因为pdf自动换页以后会把我的模块给截开,不好看甚至内容被裁开,所以我需要判断当前页面加上这个模块以后是不是会超出当前页,如果超出,就直接把整个模块换到第二页去显示。
页面大致如下:
页面代码大致如下:
<template>
<div class="child-detail-div">
<div class="title pdf-item">黄浦区适龄幼儿入园报名信息(本市)</div>
<div class="pdf-item">
<div class="table-title">报名园所</div>
<Descriptions
:data="formModel"
:columns="refChildGardenColumns"
:border="true"
></Descriptions>
<div class="pdf-item">
<div class="table-title">幼儿基础信息</div>
<Descriptions
:data="formModel.zsChildBaseInfoDto"
:columns="childBaseColumns"
:border="true"
></Descriptions>
<div class="pdf-item">
<template v-for="(item, index) in formModel.zsChildGuarderInfoDtos">
<div class="table-title" :key="'title-' + index">
家庭成员信息
<span v-if="formModel.zsChildGuarderInfoDtos.length > 1">{{
index + 1
}}</span>
<span v-if="item.defaultGuarder" class="font-15">
(主要监护人)
</span>
<Descriptions
:key="index"
:data="item"
:columns="familyColumns"
:border="true"
></Descriptions>
</template>
<div class="pdf-item">
<div class="table-title">验证材料</div>
<Descriptions
:data="formModel.childAttachmentInfoDto"
:columns="childAttachmentColumns"
:border="true"
:column="1"
></Descriptions>
<div slot="footer" class="footer-button">
<ssb-primary-button @click.native="getPdf"
>导出至PDF
</ssb-primary-button>
<ssb-default-button @click.native="dialogVisible = false"
</ssb-default-button>
</template>
<script lang="ts">
import viewTS from "./index";
export default viewTS;
</script>
如果项目中没安装html2canvas和jspdf,安装命令如下:
npm install html2canvas
npm install jspdf
1、新建文件htmlToPdf.ts
// 导出页面为PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
const a4width = 592.28; // A4的宽度,以毫米为单位
const a4Height = 841.89; // A4的高度,以毫米为单位
export async function getPdf(title: string) {
// const pdfDom: any = document.querySelector('#pdfDom');
const itemDom: any = document.querySelectorAll('.pdf-item');
const PDF = new JsPDF(undefined, 'pt', 'a4');
let position = 24; //图像的纵坐标,即左上角的y坐标
let pageItemHight = 0; //页面中item的高度
const imgData = await getImages(itemDom);
imgData.forEach((itemCanvas: any) => {
const contentWidth = itemCanvas.width;
const contentHeight = itemCanvas.height;
//一页pdf显示html页面生成的canvas高度
// const pageHeight = contentWidth / a4width * a4Height - 64;
const pageHeight = PDF.internal.pageSize.height;
const imgWidth = a4width;
const imgHeight = a4width / contentWidth * contentHeight;
const itemPageData = itemCanvas.toDataURL('image/jpeg', 1.0);
//计算页面画面高度
pageItemHight += imgHeight;
//如果加上当前item已超过当前页面高度,则另开页面
if ((pageItemHight + 48) > pageHeight) {
PDF.addPage(); //添加新页面
position = 24;
//将图像添加到PDF文档中的函数(图像的URL或base64编码的数据,指定图像的格式,图像的横坐标,图像的纵坐标,图像的宽度,图像的高度)
PDF.addImage(itemPageData, 'JPEG', 24, position, imgWidth - 48, imgHeight);
position += imgHeight; //图像的纵坐标,即左上角的y坐标
PDF.save(title + '.pdf');
function getImages(itemDom: any) {
const promises: any[] = [];
itemDom.forEach((item: any) => {
const promise = html2Canvas(item, { allowTaint: true }).then(function (canvas) {
if (canvas.height > 0) {
return canvas; // 返回Promise对象,以便集中处理
promises.push(promise);
return Promise.all(promises); // 返回一个新的Promise对象
2、vue页面对应的ts文件中引入上面写的ts文件
import { getPdf } from '@/core/utils/htmlToPdf';
然后就可以直接通过getPdf方法调用了,示例如下:
getPdf() {
getPdf("黄浦区适龄幼儿入园报名信息"); //下载文件名
因为页面中的“验证材料”模块明显已经不能跟前面的信息完全在第一个页面显示了,所以这个时候当前模块就会如下图一样被挤压到第二页显示:
注意事项:
1、由于我是通过“pdf-item”这个类来手动标识的需要生成pdf的模块,所以在vue页面中一定要加这个,不然的话是不会给加到pdf中去的
2、我的position=24代表我从距离左边24mm的位置开始画图的,如果有不想跟我一样,可以自己改
3、“pageItemHight + 48”跟我前面的“position=24”有关,如果改了position的值,这里也要记得position*2的改
4、“imgWidth - 48”是为了左右各预留24mm的位置,如果想改左右预留位置就直接改48这个数值就好
遗留问题:
我想的是除了左右预留24mm的位置外,上下也能预留24的来,但是目前感觉只实现了上面的预留,下面还不行,看下次还能怎么改。