前端打印生成pdf
以下打印均为使用a4纸格式生成pdf
1,空白页
1.1,图片前空白页
多张图片(大于3)连续出现,可能出现连续的图片被放在一起,置于下一页,上一页则会出现空白页(正常情况应该是上一页只有一张图,下一页顶部是两张图;但是,结果上一页留白,下一页顶部是三张图)
解决:
①,img 添加float样式
1.2,内容的最后位置出现空白页
解决:
①,调整页边距可能会导致出现空白页情况,故而可调整页边距可能解决
1.3,文字内容少或者以文字结尾,则后面出现空白页
(发现,如果内容部分是以图片结尾的,则不会出现额外的空白页现象)
解决:
①,向页面末尾添加`<img alt="" style="width:0;height:0">`,即使用空图展位
2,问题:
①,使用float容易出现,多张图片连续一起 出现在下一页(但是上一页还有空间至少可以排放一张图的),添加flex colomn布局可以解决,但是flex容易出现截断问题
2.1,图片截断
2.1.1,以下布局容易出现截断情况
①,图片用flex布局,容易出现截断情况
②,position绝对定位布局,也容易发生截断情况
解决:
①,使用float布局
②,使用table-row布局
③,使用下列图片样式
img {
display: inline-block;
page-break-inside: avoid;
max-width: 100%;
}
3,基于puppeteer.js搭建node服务器,生成pdf文件
需要自己搭建一套nodejs服务,专门用于生成pdf,页面需要使用html先绘制出来,通过html链接,puppeteer讲html生成对应pdf
// puppeteer 库会下载自带chrome,使用自带chrome启动并渲染
const puppeteer = require('puppeteer')
const fs = require('fs')
const sleep = async function (timeout) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve()
}, timeout)
})
}
const html2pdf = async function (
reqParams,
timeout,
printDelay,
checkPdfRenderCompleteJs
) {
try {
const { url: pageUrl, showMargin } = reqParams
const token =
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDc4NTI4MzgsInVzZXJJZCI6IjEwMDAwMjE4NyJ9.oDZ6x1e5kZnv1TxFf0cuj03a0eToeLKUdeyMSmoIIbc'
const whiteList = ['api.g2s.cn', 'orgapi.g2s.cn', 'aries-app.g2s.cn']
const browser = await puppeteer.launch({
headless: true,
// slowMo: 350, // slow down by 250ms
dumpio: true,
devtools: false,
timeout: timeout + 5,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-gpu',
'--disable-extensions',
'--mute-audio',
'–-no-first-run',
'--ignore-certificate-errors',
],
})
const page = await browser.newPage()
await page.setViewport({
width: 750,
height: 1000,
})
// page.on('console', (m) => {
// console.log('页面内日志***:' + m.text())
// })
page.setJavaScriptEnabled(true)
// await page.setRequestInterception(true)
// page.setExtraHTTPHeaders({ access_token: token })
// page.on('request', async function (req) {
// if (req.resourceType() === ['xhr']) {
// whiteList.forEach((v) => {
// if (!req.url().includes(v)) {
// req.headers({ access_token: token })
// }
// })
// // console.log('xhr 请求')
// }
// // console.log('req:', {
// // url: req.url(),
// // resourceType: req.resourceType(),
// // headers: req.headers(),
// // })
// await req.continue()
// })
// page.on('requestfinished', function (req) {
// // console.log('requestfinished:', req)
// })
const option = {
// landscape : false,
printBackground: true,
format: 'a4',
scale: 1,
// paperWidth : '1mm',
// paperHeight : '1mm',
// Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages.
pageRanges: '',
title: '',
// Whether to silently ignore invalid but successfully parsed page ranges, such as '3-2'. Defaults to false.
ignoreInvalidPageRanges: false,
// HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them:
// date: formatted print date
// title: document title
// url: document location
// pageNumber: current page number
// totalPages: total pages in the document
// For example, <span class=title></span> would generate span containing the title.
// Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
preferCSSPageSize: true,
// Allowed Values: ReturnAsBase64, ReturnAsStream
transferMode: 'ReturnAsStream',
}
if (showMargin) {
Object.assign(option, {
margin: {
top: '44px',
bottom: '74px',
left: '44px',
right: '44px',
},
displayHeaderFooter: true,
headerTemplate: `<span class=""></span>`,
footerTemplate: `
<style>
section {
width:100%;
padding:0 44px;
font-family: "宋体";
font-size: 12px;
color: #333333;
font-weight: 400;
text-align: center;
}
</style>
<section>
第 <span class="pageNumber"></span> 页 共 <span class="totalPages"></span> 页
</section>`,
})
}
// option.path = savePath
// page.setViewport({
// width: 794,
// height: 1123
// })
// const login = async function (token) {
// const windowHandle = await page.evaluateHandle(() => {
// console.log('localStorage', localStorage)
// localStorage.setItem('shine-admin-web-zhishi-token', token)
// })
// console.log('windowHandle', windowHandle)
// }
const waitPdfRenderComplete = async function (timeout) {
let time = 0
return new Promise(function (resolve, reject) {
const t = setInterval(function () {
time += 500
page
.evaluate(
checkPdfRenderCompleteJs ||
'window.document.readyState === "complete"'
)
.then(function (isOk) {
if (isOk) {
clearInterval(t)
resolve('html 解析完成-成功')
}
})
if (time > timeout) {
setTimeout(function () {
clearInterval(t)
reject('html 解析完成-失败 timeout')
}, 20)
}
}, 500)
})
}
// console.log('open url:' + pageUrl)
// await login(token)
await page.goto(pageUrl, { waitUntil: 'networkidle2' })
console.log('wait pdf render ...')
const val = await waitPdfRenderComplete(timeout)
console.log('html 解析完成', val)
console.log('print delay:' + printDelay)
await sleep(printDelay)
// console.log('save pdf file:' + savePath)
const buf = await page.pdf(option)
await page.close()
await browser.close()
return buf
} catch (error) {
console.log('生成pdf错误:', error)
// process.exit(1)
throw error
}
}
module.exports = html2pdf
4,基于pdfjs 生成pdf文件
打不死的小强

浙公网安备 33010602011771号