20行代码,零插件,前端页面导出 PDF

174 阅读1分钟

打印的场景为使用 element-plus 的 drawer 组件中的内容,类似于

<template>
  <el-button type="primary" style="margin-left: 16px" @click="drawer = true">
    open
  </el-button>

  <el-drawer
    v-model="drawer"
    title="I am the title"
    :before-close="handleClose"
    :size="'80%'"
  >
    <span>Hi, there!</span>
  </el-drawer>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const drawer = ref(false)
const handleClose = (done: () => void) => {
  drawer.value = false
}
</script>

image.png

干前端的,相信大家都知道 html2canvas 中插件。起先是使用这个插件的,但是这个插件在项目中的表现确实很差劲,会出现错位,打印不全等等各种问题。

image.png


最终决定尝试原生的 window.print() 方法

大体的思路即是

1、创建一个新的 div

2、将本来在 drawer 中的 dom 添加到新创建的 div 中

3、调用打印函数之后,再将样式进行还原。

export const exportPdf = async (el: HTMLElement, option: any) => {
  const printDiv = document.createElement('div')
  printDiv.innerHTML = el!.innerHTML
  printDiv.className = el.className
  document.body.appendChild(printDiv)
  // 设置样式
  window.document.title = `XXXXX`
  window.app.style.display = 'none'

  // 延时打印
  await window.delay(20)
  // 打印
  window.print()
  // 还原样式
  window.app.style.display = 'block'
  window.document.title = 'XXXXX'
  // 删除节点
  document.body.removeChild(printDiv)

  return true
}

调用

<template>
  <div ref="detailRef">
    // ....
    <el-button @click="handleClickExportPDF">导出PDF</el-button>
  </div>
</template>

<script setup lang="ts">
import { exportPdf } from '@/utils'

const detailRef = ref()
const handleClickExportPDF = async () => {
  await exportPdf(detailRef.value, 'title')
}
</script>