繁体   English   中英

html转pdf:html内容溢出时如何动态添加页面到pdf? (动态多页 pdf)

[英]Converting html to pdf: how to dynamically add pages to pdf when html content is overflowing? (dynamic multiple page pdf)

我正在使用 Handlebars 和 Puppeteer 将 html 编译成动态.pdf发票。 有时发票会变得相当大(2-3 页)。 结果,溢出的 html 内容被截断,请参见此图: 这个图片

我已经用我的所有代码和问题制作了一个 github 回购协议,如果您有兴趣可以在这里查看(在read.me中运行项目的说明)。

所以我试图解决这个问题的方法是,在 Handlebars 渲染我的模板之后,我启动一个带有 puppeteer 的无头浏览器,并将渲染的 html 设置为页面。

//renderTemplate is a function that reads the .hbs file and compiles the template to html.
const html = renderTemplate(data)

await page.setContent(html, {
  waitUntil: 'load'
})

然后我跟踪高度:

const heightTracker = await page.$(".height-tracker");
const heightTrackerDimensions = await heightTracker.boundingBox()

如果这个高度超过,比如说 1100,那么必须添加一个新页面并且我的订单数组中的最后item必须从 html 中剪切并粘贴到新页面。 我能想到的最好的是这样的:

 if (heightTrackerDimensions.height > 1100) {
    let pageIndex = 0;
    let height = 0;

    let sections = await page.$$(".item");
    for (let i = 0; i < sections.length; i++) {
      const sectionDimensions = await sections[i].boundingBox();

      if (height + sectionDimensions.height > 1100) {
        pageIndex++;
        console.log(i)

        await page.evaluate(() => {
          let sections = document.querySelectorAll(`.item`)
          const page = document.querySelector('.page1')
          page.insertAdjacentHTML('afterend', `
              <div style="page-break-after: always;"></div>
              <div class="invoice page2">
               <div class="invoice-inner">
                 <div class="invoice-body">
                   <div class="main-column">
                    <div class="height-tracker">
                      ${sections[i].innerHTML}
                    </div>
                   </div>
                  <div class="secondary-column">
                 </div>
                </div>
               </div>
              </div>
          `
          )
          sections[i].remove()
        });
        height += sectionDimensions.height
      } else {
        height += sectionDimensions.height
      }
    }
  }

但这只是效果不佳,一旦有更多项目从第 1 页溢出时就会中断。也许我过于复杂了。 也许有更简单的方法来实现相同的目标?

我只是为这个问题而烦恼。 我怎样才能使溢出的 html 内容自动添加到具有适当边距和填充的新 pdf 页面? 我还有哪些其他选择? 我不可能是唯一一个使用 Puppeteer 处理多页 pdf 的人......

我遇到了与 PDF 代相同的问题,尽管不完全是在相同的上下文中。

我玩过你的代码,并做了一些改变,主要是为了让 Puppeteer 自己创建需要的页面,希望能简化事情:

async function printPDF() {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  const orders = [
    { item: "Completely new website design to your company style", price: "$300" },
    { item: "Conversions optimalization and management of conversions", price: "$300" },
    { item: "Implementation of content management system - Wordpress", price: "$300" },
    { item: "Installation of Premium Wordpress Theme yearly renewed (Divi)", price: "$300" },
    { item: "Responsive desktop / mobile / tablet", price: "$300" },
    { item: "Loadspeed optimized", price: "$300" },
    { item: "Free service contract (1 year)", price: "$300" },
    { item: "Media Manager", price: "$300" },
    { item: "Google Maps", price: "$300" },
    { item: "Contactforms", price: "$300" },
    { item: "Search Engine indexation", price: "$300" },
    { item: "Google Analytics / Google search console implementation", price: "$300" },
  ];

  const data = {
    invoiceNumber: "123123123",
    company: "Acme Corp",
    orders: orders,
    total: orders.reduce((sum, order) => sum + (+order.price.replace("$", "")) , 0)
  }

  page.on('console', consoleObj => console.log(consoleObj.text()));

  const html = renderTemplate(data)
  await page.emulateMediaType('print');
  await page.setContent(html, {
    waitUntil: 'load'
  })

  const pdf = await page.pdf({
    format: 'A4',
    printBackground: true,
    margin: {
        top: "10mm",
        right: "10mm",
        bottom: "10mm",
        left: "10mm"
    },
    format: "A4"
  })

  
  await browser.close();
  return pdf

}

我还在 template.hbs 中更新了 the.invoice class(只是为了删除 height 和 max-height 项目):

.invoice {
  background-color: white;
  position: relative;
  background-size: cover;
  display: flex;
  flex-direction: column;
  width: 210mm;
  /*height: 297mm; */
  min-width: 210mm;
  min-height: 297mm;
  max-width: 210mm;
  /*max-height: 297mm; */
  font-variant-ligatures: none !important;
  -webkit-font-smoothing: antialiased !important;
  text-rendering: geometricprecision !important;
  overflow: hidden;
  background-repeat: no-repeat;
  background-position: center center;
}

以及总金额:

<tr class="total">
    <td></td>
    <td>
        Total: ${{ total }}
    </td>
</tr>

一个例子在这里: https://dropmefiles.com/xRuqY

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM