以下打印均為使用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文件
