安装两个库
Shell
pnpm install html2canvas jspdfpnpm install html2canvas jspdf函数代码
能有效防止分页文字截断的问题
JavaScript
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
/**
* 按照A4纸分页生成PDF
* @param {HTMLElement} ele - 需要导出pdf的容器元素(dom节点 不是id)
* @param {string} [pdfFileName] - 导出文件的名字
* @param {Object} [options] - 配置选项
* @param {number} [options.width=595.28] - A4纸宽度
* @param {number} [options.height=841.89] - A4纸高度
* @param {number} [options.scale=3] - 缩放层级,提高清晰度
* @param {number} [options.margin=0] - 纸张左右边距
* @param {string} [options.splitClassName] - 避免分段截断的类名,当pdf有多页时需要传入此参数
* @param {HTMLElement} [options.header] - 页眉元素
* @param {HTMLElement} [options.footer] - 页脚元素
* @param {string} [options.direction='p'] - 'p' 或 'l',默认 'p'(纵向),'l' 为横向
* @param {string} [options.outputType='save'] - 'save' | 'file' | 'blob' 等,默认 'save'
* @returns {Promise} PDF生成结果
*/
export const PagingDownPDF = async (ele, pdfFileName = null, options = {}) => {
const {
width = 595.28,
height = 841.89,
scale = 3,
margin = 20,
splitClassName = '',
header = null,
footer = null,
direction = 'p',
outputType = 'save',
} = options;
if (!(ele instanceof HTMLElement)) {
throw new TypeError('element节点请传入dom节点');
}
// 内部状态变量
const state = {
element: ele,
contentWidth: width - margin,
contentHeaderWidth: width - margin,
contentFooterWidth: width - margin,
outputType: outputType,
fileName: pdfFileName || '导出的pdf文件',
scale: scale,
baseY: 15,
isTransformBaseY: false,
header: header,
footer: footer,
direction: direction,
A4_WIDTH: width,
A4_HEIGHT: height,
splitClassName: splitClassName,
pdfFooterHeight: 0,
pdfHeaderHeight: 0,
pdf: null,
rate: 1,
pages: [],
canvasEle: null,
__header: null,
__footer: null,
originalPageHeight: 0,
};
if (state.direction === 'l') {
[state.A4_HEIGHT, state.A4_WIDTH] = [state.A4_WIDTH, state.A4_HEIGHT];
}
// 内部工具函数
const loadImage = (url) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;
img.onload = () => resolve(img);
img.onerror = () => reject(new Error('图像加载失败'));
});
};
const toCanvas = async (element, width) => {
let canvas = await html2canvas(element, {
allowTaint: true,
scale: state.scale || window.devicePixelRatio * 2,
useCORS: true,
});
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const height = (width / canvasWidth) * canvasHeight;
const canvasData = canvas.toDataURL('image/jpeg', 1.0);
canvas = null;
return { width, height, data: canvasData };
};
const createAndDisplayCanvas = async () => {
const imgData = await toCanvas(state.element, state.contentWidth);
const canvasEle = document.createElement('canvas');
canvasEle.width = imgData.width;
canvasEle.height = imgData.height;
canvasEle.style.position = 'fixed';
canvasEle.style.top = '0';
canvasEle.style.right = '0';
state.canvasEle = canvasEle;
document.body.appendChild(canvasEle);
const ctx = canvasEle.getContext('2d');
const img = await loadImage(imgData.data);
ctx.drawImage(img, 0, 0, imgData.width, imgData.height);
scan(ctx, imgData);
};
const scan = (ctx, imgData) => {
if (!ctx || !imgData) {
throw new Error('Invalid arguments: ctx or imgData is null/undefined');
}
// 从内容底部开始向上扫描,找到实际内容结束位置
let scanPosition = imgData.height - 1; // 从底部开始扫描
let contentEndPosition = imgData.height; // 记录内容实际结束位置
// 向上扫描找到最后一个非空白行
while (scanPosition >= 0) {
const imageData = ctx.getImageData(0, scanPosition, imgData.width, 1);
const uniqueArr = Array.from(new Set(imageData.data));
// 如果不是空白行(即包含内容)
if (uniqueArr.length > 1) {
contentEndPosition = scanPosition + 1; // 找到内容实际结束位置
break;
}
scanPosition--;
}
// 如果整个内容都是空白,则只有一页
if (contentEndPosition === 0) {
state.pages = [0];
if (state.canvasEle) {
state.canvasEle.remove();
state.canvasEle = null;
}
return;
}
// 根据实际内容高度计算分页
const pageHeight = parseInt(state.originalPageHeight, 10);
let currentPageEnd = pageHeight;
state.pages = [0]; // 重置分页数组
while (currentPageEnd < contentEndPosition) {
// 在当前分页点附近寻找最佳分割点(空白区域)
let bestSplitPoint = currentPageEnd;
const searchStart = Math.max(currentPageEnd - 50, 0); // 向前搜索50像素
const searchEnd = Math.min(currentPageEnd + 50, contentEndPosition); // 向后搜索50像素
// 在搜索范围内寻找空白区域作为分割点
for (let y = searchStart; y < searchEnd; y++) {
const imageData = ctx.getImageData(0, y, imgData.width, 1);
const uniqueArr = Array.from(new Set(imageData.data));
if (uniqueArr.length === 1 && y > state.pages[state.pages.length - 1] + pageHeight * 0.8) {
// 找到空白区域,且在当前页的80%之后
bestSplitPoint = y;
break;
}
}
state.pages.push(bestSplitPoint);
currentPageEnd = bestSplitPoint + pageHeight;
}
// 检查最后一页是否内容太少,如果是则不创建该页
const lastPageContentHeight = contentEndPosition - state.pages[state.pages.length - 1];
if (lastPageContentHeight < pageHeight * 0.1 && state.pages.length > 1) {
// 如果最后一页内容少于10%的页面高度,且不是第一页,则移除最后一页
state.pages.pop();
}
// 清理临时canvas
if (state.canvasEle) {
state.canvasEle.remove();
state.canvasEle = null;
}
};
const preventSplitElements = (pageHeight) => {
if (!state.splitClassName) return;
const elements = state.element.querySelectorAll(`.${state.splitClassName}`);
const containerTop = state.element.getBoundingClientRect().top;
elements.forEach((el) => {
const rect = el.getBoundingClientRect();
const offsetTop = rect.top - containerTop;
const bottom = offsetTop + rect.height;
const startPage = Math.floor(offsetTop / pageHeight);
const endPage = Math.floor(bottom / pageHeight);
if (startPage !== endPage) {
const placeholder = document.createElement('div');
placeholder.className = 'pdf-split-placeholder';
placeholder.style.height = startPage * pageHeight - offsetTop + 'px';
placeholder.style.width = '100%';
el.parentNode.insertBefore(placeholder, el);
}
});
};
const addImage = (_x, _y, pdf, data, width, height) => {
pdf.addImage(data, 'JPEG', _x, _y, width, height);
};
const addBlank = (x, y, width, height, pdf) => {
pdf.setFillColor(255, 255, 255);
pdf.rect(x, y, Math.ceil(width), Math.ceil(height), 'F');
};
const addHeader = async (pageNo, header, pdf, contentWidth) => {
if (!header || !(header instanceof HTMLElement)) {
return;
}
if (!state.__header) {
state.__header = await toCanvas(header, contentWidth);
}
const { height, data } = state.__header;
const leftX = (state.A4_WIDTH - state.contentHeaderWidth) / 2;
pdf.addImage(data, 'JPEG', leftX, 0, contentWidth, height);
};
const addFooter = async (pageSize, pageNo, footer, pdf, contentWidth) => {
if (!footer || !(footer instanceof HTMLElement)) {
return;
}
const pageNoDom = footer.querySelector('.pdf-footer-page');
const pageSizeDom = footer.querySelector('.pdf-footer-page-count');
if (pageNoDom) {
pageNoDom.innerText = pageNo;
}
if (pageSizeDom) {
pageSizeDom.innerText = pageSize;
}
if (pageNoDom || !state.__footer) {
state.__footer = await toCanvas(footer, contentWidth);
}
const leftX = (state.A4_WIDTH - state.contentFooterWidth) / 2;
const { height, data } = state.__footer;
pdf.addImage(data, 'JPEG', leftX, state.A4_HEIGHT - height, contentWidth, height);
};
const getPdfByType = (pdf) => {
let result = null;
switch (state.outputType) {
case 'file':
result = new File([pdf.output('blob')], state.fileName, {
type: 'application/pdf',
lastModified: Date.now(),
});
break;
case 'save':
result = pdf.save(state.fileName);
break;
default:
result = pdf.output(state.outputType);
}
return result;
};
// 主要的PDF生成逻辑
// 滚动置顶,防止顶部空白
window.pageYOffset = 0;
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
return new Promise(async (resolve, reject) => {
// jsPDF实例
const pdf = new jsPDF({
unit: 'pt',
format: 'a4',
orientation: state.direction,
});
state.pdf = pdf;
let pdfFooterHeight = 0;
let pdfHeaderHeight = 0;
// 距离PDF左边的距离,/ 2 表示居中 ,,预留空间给左边, 右边,也就是左右页边距
const baseX = (state.A4_WIDTH - state.contentWidth) / 2;
// 距离PDF 页眉和页脚的间距, 留白留空
let baseY = state.baseY;
// 元素在网页页面的宽度
const elementWidth = state.element.scrollWidth;
// PDF内容宽度 和 在HTML中宽度 的比, 用于将 元素在网页的高度 转化为 PDF内容内的高度, 将 元素距离网页顶部的高度 转化为 距离Canvas顶部的高度
const rate = state.contentWidth / elementWidth;
state.rate = rate;
if (state.isTransformBaseY) {
state.baseY = baseY = baseY * rate;
}
// 页脚元素 经过转换后在PDF页面的高度
if (state.footer) {
pdfFooterHeight = (await toCanvas(state.footer, state.contentFooterWidth)).height;
state.pdfFooterHeight = pdfFooterHeight;
}
// 页眉元素 经过转换后在PDF的高度
if (state.header) {
pdfHeaderHeight = (await toCanvas(state.header, state.contentHeaderWidth)).height;
state.pdfHeaderHeight = pdfHeaderHeight;
}
// 除去页头、页眉、还有内容与两者之间的间距后 每页内容的实际高度
const originalPageHeight = state.A4_HEIGHT - pdfFooterHeight - pdfHeaderHeight - 2 * baseY;
state.originalPageHeight = originalPageHeight;
// 处理 splitClassName 元素,避免被分页截断
preventSplitElements(originalPageHeight / state.rate);
state.pages = [0]; // 要从0开始
// 计算分页
await createAndDisplayCanvas();
const pages = state.pages;
const { width, height, data } = await toCanvas(state.element, state.contentWidth);
// 扫描函数已经处理了所有分页逻辑,这里不再需要额外的分页判断
// 根据分页位置 开始分页生成pdf
for (let i = 0; i < pages.length; ++i) {
// 页眉高度
const pdfHeaderH = pdfHeaderHeight;
// 页脚高度
const pdfFooterH = pdfFooterHeight;
// 根据分页位置新增图片,要排除页眉和顶部留白
addImage(baseX, baseY + pdfHeaderH - pages[i], pdf, data, width, height);
// 将 内容 与 页眉之间留空留白的部分进行遮白处理
addBlank(0, pdfHeaderH, state.A4_WIDTH, baseY, pdf);
// 将 内容 与 页脚之间留空留白的部分进行遮白处理
addBlank(0, state.A4_HEIGHT - baseY - pdfFooterH, state.A4_WIDTH, baseY, pdf);
// 对于除最后一页外,对 内容 的多余部分进行遮白处理
if (i < pages.length - 1) {
// 获取当前页面需要的内容部分高度
const imageHeight = pages[i + 1] - pages[i];
// 对多余的内容部分进行遮白,但只在当前页面内容不足一页时进行遮白
if (imageHeight < originalPageHeight) {
addBlank(
0,
baseY + imageHeight + pdfHeaderH,
state.A4_WIDTH,
state.A4_HEIGHT - imageHeight,
pdf,
);
}
}
// 添加页眉
await addHeader(i + 1, state.header, pdf, state.contentHeaderWidth);
// 添加页脚
await addFooter(pages.length, i + 1, state.footer, pdf, state.contentFooterWidth);
// 若不是最后一页,则分页
if (i !== pages.length - 1) {
// 增加分页
pdf.addPage();
}
}
try {
const result = await getPdfByType(pdf);
// 清理插入的占位符
const placeholders = state.element.querySelectorAll('.pdf-split-placeholder');
placeholders.forEach((el) => el.remove());
resolve({
pdfResult: result,
});
} catch (error) {
reject('生成pdf出错', error);
}
});
};import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
/**
* 按照A4纸分页生成PDF
* @param {HTMLElement} ele - 需要导出pdf的容器元素(dom节点 不是id)
* @param {string} [pdfFileName] - 导出文件的名字
* @param {Object} [options] - 配置选项
* @param {number} [options.width=595.28] - A4纸宽度
* @param {number} [options.height=841.89] - A4纸高度
* @param {number} [options.scale=3] - 缩放层级,提高清晰度
* @param {number} [options.margin=0] - 纸张左右边距
* @param {string} [options.splitClassName] - 避免分段截断的类名,当pdf有多页时需要传入此参数
* @param {HTMLElement} [options.header] - 页眉元素
* @param {HTMLElement} [options.footer] - 页脚元素
* @param {string} [options.direction='p'] - 'p' 或 'l',默认 'p'(纵向),'l' 为横向
* @param {string} [options.outputType='save'] - 'save' | 'file' | 'blob' 等,默认 'save'
* @returns {Promise} PDF生成结果
*/
export const PagingDownPDF = async (ele, pdfFileName = null, options = {}) => {
const {
width = 595.28,
height = 841.89,
scale = 3,
margin = 20,
splitClassName = '',
header = null,
footer = null,
direction = 'p',
outputType = 'save',
} = options;
if (!(ele instanceof HTMLElement)) {
throw new TypeError('element节点请传入dom节点');
}
// 内部状态变量
const state = {
element: ele,
contentWidth: width - margin,
contentHeaderWidth: width - margin,
contentFooterWidth: width - margin,
outputType: outputType,
fileName: pdfFileName || '导出的pdf文件',
scale: scale,
baseY: 15,
isTransformBaseY: false,
header: header,
footer: footer,
direction: direction,
A4_WIDTH: width,
A4_HEIGHT: height,
splitClassName: splitClassName,
pdfFooterHeight: 0,
pdfHeaderHeight: 0,
pdf: null,
rate: 1,
pages: [],
canvasEle: null,
__header: null,
__footer: null,
originalPageHeight: 0,
};
if (state.direction === 'l') {
[state.A4_HEIGHT, state.A4_WIDTH] = [state.A4_WIDTH, state.A4_HEIGHT];
}
// 内部工具函数
const loadImage = (url) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;
img.onload = () => resolve(img);
img.onerror = () => reject(new Error('图像加载失败'));
});
};
const toCanvas = async (element, width) => {
let canvas = await html2canvas(element, {
allowTaint: true,
scale: state.scale || window.devicePixelRatio * 2,
useCORS: true,
});
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const height = (width / canvasWidth) * canvasHeight;
const canvasData = canvas.toDataURL('image/jpeg', 1.0);
canvas = null;
return { width, height, data: canvasData };
};
const createAndDisplayCanvas = async () => {
const imgData = await toCanvas(state.element, state.contentWidth);
const canvasEle = document.createElement('canvas');
canvasEle.width = imgData.width;
canvasEle.height = imgData.height;
canvasEle.style.position = 'fixed';
canvasEle.style.top = '0';
canvasEle.style.right = '0';
state.canvasEle = canvasEle;
document.body.appendChild(canvasEle);
const ctx = canvasEle.getContext('2d');
const img = await loadImage(imgData.data);
ctx.drawImage(img, 0, 0, imgData.width, imgData.height);
scan(ctx, imgData);
};
const scan = (ctx, imgData) => {
if (!ctx || !imgData) {
throw new Error('Invalid arguments: ctx or imgData is null/undefined');
}
// 从内容底部开始向上扫描,找到实际内容结束位置
let scanPosition = imgData.height - 1; // 从底部开始扫描
let contentEndPosition = imgData.height; // 记录内容实际结束位置
// 向上扫描找到最后一个非空白行
while (scanPosition >= 0) {
const imageData = ctx.getImageData(0, scanPosition, imgData.width, 1);
const uniqueArr = Array.from(new Set(imageData.data));
// 如果不是空白行(即包含内容)
if (uniqueArr.length > 1) {
contentEndPosition = scanPosition + 1; // 找到内容实际结束位置
break;
}
scanPosition--;
}
// 如果整个内容都是空白,则只有一页
if (contentEndPosition === 0) {
state.pages = [0];
if (state.canvasEle) {
state.canvasEle.remove();
state.canvasEle = null;
}
return;
}
// 根据实际内容高度计算分页
const pageHeight = parseInt(state.originalPageHeight, 10);
let currentPageEnd = pageHeight;
state.pages = [0]; // 重置分页数组
while (currentPageEnd < contentEndPosition) {
// 在当前分页点附近寻找最佳分割点(空白区域)
let bestSplitPoint = currentPageEnd;
const searchStart = Math.max(currentPageEnd - 50, 0); // 向前搜索50像素
const searchEnd = Math.min(currentPageEnd + 50, contentEndPosition); // 向后搜索50像素
// 在搜索范围内寻找空白区域作为分割点
for (let y = searchStart; y < searchEnd; y++) {
const imageData = ctx.getImageData(0, y, imgData.width, 1);
const uniqueArr = Array.from(new Set(imageData.data));
if (uniqueArr.length === 1 && y > state.pages[state.pages.length - 1] + pageHeight * 0.8) {
// 找到空白区域,且在当前页的80%之后
bestSplitPoint = y;
break;
}
}
state.pages.push(bestSplitPoint);
currentPageEnd = bestSplitPoint + pageHeight;
}
// 检查最后一页是否内容太少,如果是则不创建该页
const lastPageContentHeight = contentEndPosition - state.pages[state.pages.length - 1];
if (lastPageContentHeight < pageHeight * 0.1 && state.pages.length > 1) {
// 如果最后一页内容少于10%的页面高度,且不是第一页,则移除最后一页
state.pages.pop();
}
// 清理临时canvas
if (state.canvasEle) {
state.canvasEle.remove();
state.canvasEle = null;
}
};
const preventSplitElements = (pageHeight) => {
if (!state.splitClassName) return;
const elements = state.element.querySelectorAll(`.${state.splitClassName}`);
const containerTop = state.element.getBoundingClientRect().top;
elements.forEach((el) => {
const rect = el.getBoundingClientRect();
const offsetTop = rect.top - containerTop;
const bottom = offsetTop + rect.height;
const startPage = Math.floor(offsetTop / pageHeight);
const endPage = Math.floor(bottom / pageHeight);
if (startPage !== endPage) {
const placeholder = document.createElement('div');
placeholder.className = 'pdf-split-placeholder';
placeholder.style.height = startPage * pageHeight - offsetTop + 'px';
placeholder.style.width = '100%';
el.parentNode.insertBefore(placeholder, el);
}
});
};
const addImage = (_x, _y, pdf, data, width, height) => {
pdf.addImage(data, 'JPEG', _x, _y, width, height);
};
const addBlank = (x, y, width, height, pdf) => {
pdf.setFillColor(255, 255, 255);
pdf.rect(x, y, Math.ceil(width), Math.ceil(height), 'F');
};
const addHeader = async (pageNo, header, pdf, contentWidth) => {
if (!header || !(header instanceof HTMLElement)) {
return;
}
if (!state.__header) {
state.__header = await toCanvas(header, contentWidth);
}
const { height, data } = state.__header;
const leftX = (state.A4_WIDTH - state.contentHeaderWidth) / 2;
pdf.addImage(data, 'JPEG', leftX, 0, contentWidth, height);
};
const addFooter = async (pageSize, pageNo, footer, pdf, contentWidth) => {
if (!footer || !(footer instanceof HTMLElement)) {
return;
}
const pageNoDom = footer.querySelector('.pdf-footer-page');
const pageSizeDom = footer.querySelector('.pdf-footer-page-count');
if (pageNoDom) {
pageNoDom.innerText = pageNo;
}
if (pageSizeDom) {
pageSizeDom.innerText = pageSize;
}
if (pageNoDom || !state.__footer) {
state.__footer = await toCanvas(footer, contentWidth);
}
const leftX = (state.A4_WIDTH - state.contentFooterWidth) / 2;
const { height, data } = state.__footer;
pdf.addImage(data, 'JPEG', leftX, state.A4_HEIGHT - height, contentWidth, height);
};
const getPdfByType = (pdf) => {
let result = null;
switch (state.outputType) {
case 'file':
result = new File([pdf.output('blob')], state.fileName, {
type: 'application/pdf',
lastModified: Date.now(),
});
break;
case 'save':
result = pdf.save(state.fileName);
break;
default:
result = pdf.output(state.outputType);
}
return result;
};
// 主要的PDF生成逻辑
// 滚动置顶,防止顶部空白
window.pageYOffset = 0;
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
return new Promise(async (resolve, reject) => {
// jsPDF实例
const pdf = new jsPDF({
unit: 'pt',
format: 'a4',
orientation: state.direction,
});
state.pdf = pdf;
let pdfFooterHeight = 0;
let pdfHeaderHeight = 0;
// 距离PDF左边的距离,/ 2 表示居中 ,,预留空间给左边, 右边,也就是左右页边距
const baseX = (state.A4_WIDTH - state.contentWidth) / 2;
// 距离PDF 页眉和页脚的间距, 留白留空
let baseY = state.baseY;
// 元素在网页页面的宽度
const elementWidth = state.element.scrollWidth;
// PDF内容宽度 和 在HTML中宽度 的比, 用于将 元素在网页的高度 转化为 PDF内容内的高度, 将 元素距离网页顶部的高度 转化为 距离Canvas顶部的高度
const rate = state.contentWidth / elementWidth;
state.rate = rate;
if (state.isTransformBaseY) {
state.baseY = baseY = baseY * rate;
}
// 页脚元素 经过转换后在PDF页面的高度
if (state.footer) {
pdfFooterHeight = (await toCanvas(state.footer, state.contentFooterWidth)).height;
state.pdfFooterHeight = pdfFooterHeight;
}
// 页眉元素 经过转换后在PDF的高度
if (state.header) {
pdfHeaderHeight = (await toCanvas(state.header, state.contentHeaderWidth)).height;
state.pdfHeaderHeight = pdfHeaderHeight;
}
// 除去页头、页眉、还有内容与两者之间的间距后 每页内容的实际高度
const originalPageHeight = state.A4_HEIGHT - pdfFooterHeight - pdfHeaderHeight - 2 * baseY;
state.originalPageHeight = originalPageHeight;
// 处理 splitClassName 元素,避免被分页截断
preventSplitElements(originalPageHeight / state.rate);
state.pages = [0]; // 要从0开始
// 计算分页
await createAndDisplayCanvas();
const pages = state.pages;
const { width, height, data } = await toCanvas(state.element, state.contentWidth);
// 扫描函数已经处理了所有分页逻辑,这里不再需要额外的分页判断
// 根据分页位置 开始分页生成pdf
for (let i = 0; i < pages.length; ++i) {
// 页眉高度
const pdfHeaderH = pdfHeaderHeight;
// 页脚高度
const pdfFooterH = pdfFooterHeight;
// 根据分页位置新增图片,要排除页眉和顶部留白
addImage(baseX, baseY + pdfHeaderH - pages[i], pdf, data, width, height);
// 将 内容 与 页眉之间留空留白的部分进行遮白处理
addBlank(0, pdfHeaderH, state.A4_WIDTH, baseY, pdf);
// 将 内容 与 页脚之间留空留白的部分进行遮白处理
addBlank(0, state.A4_HEIGHT - baseY - pdfFooterH, state.A4_WIDTH, baseY, pdf);
// 对于除最后一页外,对 内容 的多余部分进行遮白处理
if (i < pages.length - 1) {
// 获取当前页面需要的内容部分高度
const imageHeight = pages[i + 1] - pages[i];
// 对多余的内容部分进行遮白,但只在当前页面内容不足一页时进行遮白
if (imageHeight < originalPageHeight) {
addBlank(
0,
baseY + imageHeight + pdfHeaderH,
state.A4_WIDTH,
state.A4_HEIGHT - imageHeight,
pdf,
);
}
}
// 添加页眉
await addHeader(i + 1, state.header, pdf, state.contentHeaderWidth);
// 添加页脚
await addFooter(pages.length, i + 1, state.footer, pdf, state.contentFooterWidth);
// 若不是最后一页,则分页
if (i !== pages.length - 1) {
// 增加分页
pdf.addPage();
}
}
try {
const result = await getPdfByType(pdf);
// 清理插入的占位符
const placeholders = state.element.querySelectorAll('.pdf-split-placeholder');
placeholders.forEach((el) => el.remove());
resolve({
pdfResult: result,
});
} catch (error) {
reject('生成pdf出错', error);
}
});
};
