html-to-image + print-js 生成超长图并打印

552 阅读2分钟

需求

需要打印表格,UI组件库的表格(arco、element plus 等组件库的表格都会这问题,应该是样式太复杂)如果用原生的打印会出现样式显示不全的问题。边框也会不见
网上找到个方法 使用html2canvas把表格转成长图然后使用print-js打印

虽然html2canvas官网文档写的支持高度16384px。
但是实际使用过程中html2canvas对于比较长的内容(超过1500px)生成的canvas显示不全(画布高度可以渲染,但是内容渲染不出来)。

Chrome

Maximum height/width: 32,767 pixels Maximum area: 268,435,456 pixels (e.g., 16,384 x 16,384)

最后用html-to-image替换。10000+px高度(10多页A4纸,1MB+的图片)的元素也能轻松渲染成图片。

vue3使用

安装 html-to-image 和 print-js

yarn add html-to-image
yarn add print-js

SFC页面引入

<template>
     <button @click="print">打印</button>
     <div ref="printArea" class="printArea">
         <div data-ignore>不打印这个元素</div>
         <div v-for="(item,index) in 10000">测试{{index}}</div>
     </div>
</template>

<script setup>
import { ref, computed, h, nextTick } from 'vue'
import printJS from 'print-js'
import {toPng} from "html-to-image"
const printArea = ref()
// 打印
const print = () => {
  loading.value = true
  nextTick(() => {
    toPng(printArea.value, {
      // 过滤有data-ignore 属性的元素
      filter: (node) => {
        if (node.dataset && node.dataset.hasOwnProperty("ignore")) {
          return false
        }
        return true
      },})
      .then((dataUrl) => {
        // 下载图片
        downBase64ByBlob(dataUrl)
        // 根据图片打印
        printJS({
          printable: dataUrl,
          type: 'image',
          documentTitle: `打印标题`,
          style: 'body {margin-top: 0; background-color: #fff}',
        })
      })
      .finally(() => {
        loading.value = false
      })
  })
}

// 通过blob的方式下载base64,不会出现太大无法下载的情况
const downBase64ByBlob = (dataUrl,fileName='download',fileExtension ="png") => {
  // 将 base64 字符串转换为 Blob 对象
  const byteCharacters = atob(dataUrl.split(',')[1])
  const byteArrays = []
  for (let offset = 0; offset < byteCharacters.length; offset += 10240) {
    const slice = byteCharacters.slice(offset, offset + 10240)
    const byteNumbers = new Array(slice.length)
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i)
    }
    const byteArray = new Uint8Array(byteNumbers)
    byteArrays.push(byteArray)
  }
  const blob = new Blob(byteArrays, { type: 'application/octet-stream' })
  const blobUrl = URL.createObjectURL(blob)
  const creatDom = document.createElement('a')
  document.body.appendChild(creatDom)
  creatDom.href = blobUrl
  creatDom.download = `${fileName}.${fileExtension}`;
  creatDom.click()
  document.body.removeChild(creatDom)
  URL.revokeObjectURL(blobUrl)
}
</script>
<style scoped lang="less">
.printArea {
  max-width: 1300px; // 限制最大宽度适应A4宽度打印
}
</style>

使用效果

表格/打印元素 高度

image.png

点击打印

image.png

生成的图片

download (5).png