H5 技术 笔记 表格转PDF

1、表格转PDF

        A4纸

仿照别人,勿怪

2、代码

模块

const _pdf = ref<any>(null)
const handleExport = () =>{
  console.log('点击下载')
  const pageHeight = Math.floor(277 * _pdf.value.scrollWidth / 190) //计算pdf高度
  downloadPDF(_pdf.value, document.getElementsByClassName('item'), _batch.value + '_' + getTime(0), 30, 30, pageHeight)
}

vue

<div ref="_pdf" class="ex-pdf-box">
      <div v-for="v in _pdfList" :key="v._info._name" class="item">
        <!-- 表工序 -->
        <div class="box-head">
          <div>{{v._info._process}}</div>
          <div>{{v._info._name}}</div>
          <div>{{v._info._date}}</div>
        </div>
        <!-- 表内容 -->
        <el-table
          :header-row-style="headerRowStyle" :row-style="rowStyle"
          :data="v._table" :border="true" size="small" style="width: 100%" :highlight-current-row="true">
          <el-table-column prop="process" label="过程" width="80" header-align="center" />
<!-- ... -->
        </el-table>
      </div>
    </div>

工具方法

import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'
import { ref } from 'vue'
import { NotificationSuccess } from '../element-plus/JHNotification'

/** 导出PDF 内容: 表格
 * 
 * @param _pdfRef pdf ref
 * @param itemList 列表中的表格类名
 * @param fileName 导出的pdf的文件名
 * @param headSize 头部高度
 * @param footerSize 尾部高度
 * @param pageSize 一页高度
 */
export const downloadPDF = (_pdfRef:any, itemList:any, fileName: string, headSize: number, footerSize: number, pageHeight: number) =>{
  NotificationSuccess('开始下载')
  // console.log(fileName)
  // return
  // (1) 添加一些画面
  setPdfPage(_pdfRef, itemList, headSize, footerSize, pageHeight)
  // return

  // (2) 准备画布样式
  const style = ref<any>({
    dpi: 96, // 分辨率
    scale: 2, //设置缩放
    useCORS: true, // 允许canvas画布内 可以跨域请求外部链接图片,允许跨域请求
    bgColor: '#fff', // 背景颜色
    logging: false // 打印日志用的,可以不加默认为false
  })

  // (3) 画布
  console.log('准备画布 start')
  html2canvas(_pdfRef, style).then((canvas:any)=>{
    console.log('准备画布 end')
    canvas2Pdf(canvas, fileName, headSize, pageHeight)
  }).catch((err:any)=>{
    console.error(err)
  })
}


// 画布
/**
 * 
 * @param canvas 画布
 * @param fileName 文件名
 * @param headSize 头部高度(px, 不是画布的头部高度)
 * @param pageHeight pdf页面高度(px, 不是画布一页的高度)
 * 公式:1、+xx.toFixed(2) 保留两位小数, 记得加+(转为数值) 2、
 */
const canvas2Pdf = (canvas:any, fileName:string, headSize: number, pageHeight:number)=>{
  console.log('开始下载')
  console.log(canvas)
  // (1) 一些参数配置
  const canvasWidth = canvas.width
  const canvasHeight = canvas.height
  const _headHeight = +(595.28 / canvasWidth * headSize).toFixed(2)

  // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
  const imgwidth = 595.28
  const imgHeight = +(595.28 / canvasWidth * canvasHeight).toFixed(2)

  let position = _headHeight // 页面偏移, 刚开始是页面头部
  let residueHeight = canvasHeight // 未生成的canvas页面高度
  
  // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
  // const pageHeight = Math.floor(277 * canvas.width / 190) + 20 //计算pdf高度
  // 如果 Math.floor(277 * canvas.width / 190) !== pageHeight, 那就用公式

  // console.log('canvasWidth ==> ', canvasWidth)
  // console.log('canvasHeight ==> ', canvasHeight)
  // console.log('_headHeight ==> ', _headHeight)
  // console.log('imgwidth ==> ', imgwidth)
  // console.log('imgHeight ==> ', imgHeight)
  // console.log('canvas.width ==> ', canvas.width)
  // console.log('pageHeight ==> ', pageHeight)
  // console.log('pageHeight ==> ', Math.floor(277 * canvas.width / 190))
  

  const pageData = canvas.toDataURL('image/jpeg', 1.0)
  // 第一个参数: l:横向  p:纵向
  // 第二个参数:测量单位("pt","mm", "cm", "m", "in" or "px")
	const pdf = new jsPDF('p', 'pt', 'a4')

  if (residueHeight < pageHeight) { // 如果剩余画布高度小于一页pdf高度(最后一个了)
    // 在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示
    pdf.addImage(pageData, 'JPEG', 0, headSize, imgwidth, imgHeight)
  }
  else { // 否则,不断循环
    while(residueHeight > 0) {
      pdf.addImage(pageData, 'JPEG', 0, position, imgwidth, imgHeight)

      residueHeight -= pageHeight
      position -= +(841.89 - +(_headHeight * 5 / 7).toFixed(2)).toFixed(2) //  5/7
      // console.log('position ==> ', position)

      // 避免添加空白页
      if (residueHeight > 0) {
        pdf.addPage()
      }
    }
  }

  console.log('下载完成')
  NotificationSuccess('下载完成')
  pdf.save(fileName + ".pdf")

}


/** 计算 设置pdf页面,一些表格内容超出页面(放空页面)
 * 
 * @param _pdfRef pdf ref
 * @param itemList 列表中的表格类名
 * @param headSize 头部高度(px, 不是画布的头部高度)
 * @param footerSize 尾部高度(px, 不是画布的尾部高度)
 * @param pageSize 页面大小
 */
const setPdfPage = (_pdfRef:any, itemList:any, headSize: number, footerSize: number, pageSize: number)=>{
  console.log(_pdfRef)
  console.log(itemList)
  // a4纸的尺寸[595.28,841.89]
  let size = 0 // 相加的大小
  let addSize = 0 // 添加的页面大小

  for(let i=0; i<itemList.length; i++) {
    if (i==0) size = headSize + footerSize

    // 一个表都大于页面,先不考虑(好像目前这个没有)

    if (size + itemList[i].offsetHeight > pageSize) { // 如果大于
      addSize = pageSize - size

      console.log('i 如果大于 ===> ', i)

      i--
      size = headSize + footerSize
      

      // 添加页面
      let newNode = addFooterElement(addSize)  //向pdf插入空白块的内容
      const divParent = itemList[i].parentNode // 获取该div的父节点
      const next = itemList[i].nextSibling // 获取div的下一个兄弟节点
      // 判断兄弟节点是否存在
      if (next) {
        // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
        divParent.insertBefore(newNode, next)
      } else {
        // 否则向节点添加最后一个子节点
        divParent.appendChild(newNode)
      }
      // sum += size
    }
    // 如果小于,再试试加一个
    else {
      size += itemList[i].offsetHeight
    }
  }
}

/** 创建div
 * 
 * @param remainingHeight 插入元素的高度
 * @param fillingHeight 
 * @returns div
 */
const addFooterElement = (remainingHeight:number, fillingHeight:number = 0)=> {
  console.log('添加的div高度', remainingHeight)
  const newNode = document.createElement('div')
  newNode.style.background = '#ffffff'
  newNode.style.width = 'calc(100% + 8px)'
  newNode.style.marginLeft = '-4px'
  newNode.style.marginBottom = '0px'
  newNode.classList.add('divRemove')
  newNode.style.height = (remainingHeight + fillingHeight) + 'px'
  return newNode
}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值