使用html2pdf实现前端页面打印,批量打印导出为PDF
// 使用注意:
// 如果页面中有图片会因为跨域问题导致图片下载不下来
// 所以在图片标签中需要加入一些属性:crossOrigin 和 url后加一个随机后缀
// <Image crossOrigin="anonymous" src={`${faceInfo.user_face_url}?v=${new Date()}`} width={200} alt="" />
const { jsPDF } = window.jspdf
/**
*
* @param {*} id 要下载部分页面的元素id
* @param {*} htmlTitle 下载文件文件名称
*/
export default function (id, htmlTitle = '标题') {
let element = document.body;
if (id) {
element = document.getElementById(id);
}
return html2canvas(element, {
logging: false,
useCORS: true,
}).then(function (canvas) {
var pdf = new jsPDF('p', 'mm', 'a4'); // A4纸,纵向
var ctx = canvas.getContext('2d');
var a4w = 190;
var a4h = 257; // A4大小,210mm x 297mm,四边各保留20mm的边距
var imgHeight = Math.floor((a4h * canvas.width) / a4w); // 按A4显示比例换算一页图像的像素高度
var renderedHeight = 0;
while (renderedHeight < canvas.height) {
var page = document.createElement('canvas');
page.width = canvas.width;
page.height = Math.min(imgHeight, canvas.height - renderedHeight); // 可能内容不足一页
// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
page
.getContext('2d')
.putImageData(
ctx.getImageData(
0,
renderedHeight,
canvas.width,
Math.min(imgHeight, canvas.height - renderedHeight),
),
0,
0,
);
pdf.addImage(
page.toDataURL('image/jpeg', 1.0),
'JPEG',
10,
10,
a4w,
Math.min(a4h, (a4w * page.height) / page.width),
); // 添加图像到页面,保留10mm边距
renderedHeight += imgHeight;
if (renderedHeight < canvas.height) {
pdf.addPage();
} // 如果后面还有内容,添加一个空页
// delete page;
}
// pdf.save(htmlTitle);
var pdfBase64Str = pdf.output('datauristring'); //获取base64Pdf
var myfile = dataURLtoFile(pdfBase64Str, htmlTitle + '.pdf'); //调用一下下面的转文件流函数
return myfile;
});
}
/*
将base64转换为文件,接收2个参数,第一是base64,第二个是文件名字
最后返回文件对象
*/
const dataURLtoFile = (dataurl, filename) => {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
};
// 使用
import React, { useState, useEffect, useRef } from 'react';
import { Space, Button, Modal, Spin } from 'antd';
import { httpAdminTyreHandoverPhotoDetail } from '@/api'
import html2pdf from '@/utils/html2pdf';
import JSZip from 'jszip'
import { saveAs } from "file-saver";
import './style.less'
import ReactToPrint from 'react-to-print';
import { mmToPixels } from "@/utils/tools";
const Index = ({ selectedIds, setShow }) => {
const [data, setData] = useState({})
const ref = useRef();
const [pageLoading, set_pageLoading] = useState(false)
useEffect(async () => {
try{
set_pageLoading(true)
const list = await Promise.all(
selectedIds.map(async id => {
const res = await httpAdminTyreHandoverPhotoDetail({ id });
return res.data;
})
)
setData(list)
set_pageLoading(false)
} catch(e) {
console.error(e)
}
}, [selectedIds])
const [loading, setLoading] = useState(false)
const butns = [
<Button
disabled={pageLoading}
loading={loading}
type="primary"
onClick={async () => {
setLoading(true)
var zip = new JSZip();
await Promise.all(
data.map(async (item, index) => {
const pdfFile = await html2pdf(`batch-export-box${index}`);
zip.file(`文件:${item?.order_num}.pdf`, pdfFile);
})
)
zip.generateAsync({ type: "blob" })
.then(function (content) {
saveAs(content, "文件.zip");
});
setLoading(false)
}}
>
导出PDF文件
</Button>,
<ReactToPrint
trigger={() => <Button type="primary" disabled={pageLoading}>打印</Button>}
content={() => ref.current}
/>,
]
// A4宽度转像素
const widthPixels = mmToPixels(210); // 大约1485像素
// A4高度转像素
const heightPixels = mmToPixels(297); // 大约2105像素
return (
<Modal
open={true}
width='1200px'
onCancel={() => setShow(false)}
footer={
[
...butns,
<Button onClick={() => setShow(false)}>取消</Button>
]
}
title={<Space>
<span>批量打印</span>
{butns[0]}
{butns[1]}
</Space>}
>
<Spin spinning={pageLoading}>
<div ref={(e) => ref.current = e}>
<div style={{ width: '100%' }}>
{
data?.length ? data.map((item, index) => {
return <div
id={`batch-export-box${index}`}
style={{ padding: '12px', pageBreakAfter: 'always', width:`${widthPixels}px` }}
>
<Content info={item} />
</div>
}) : ''
}
</div>
</div>
</Spin>
</Modal>
)
}
export default Index;
const Content = ({info}) => {
return <div className='PDFDescriptions' style={{width: '100%'}} direction="vertical">
内容
</div>
}
原文地址:https://blog.csdn.net/weixin_46554760/article/details/140603464
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!