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