前端打印生成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文件

 

posted @ 2022-03-28 15:49  不忘初心dbsdxq  阅读(811)  评论(0编辑  收藏  举报
TOP 文章底部