将图表和表格导出为PDF的功能

复制代码
<template>
  <div>
    <div
      ref="pdfContent"
      style="position: relative; width: 800px; margin: 0 auto"
    >
      <!-- ECharts 图表 -->
      <div id="chart" style="width: 100%; height: 400px" />

      <!-- Element UI 表格 -->
      <el-table
        ref="myTable"
        :data="tableData"
        style="width: 100%; margin-top: 20px"
        border
        stripe
      >
        <el-table-column prop="date" label="日期" width="180" />
        <el-table-column prop="name" label="姓名" width="180" />
        <el-table-column prop="address" label="地址" />
      </el-table>
    </div>
    <button @click="exportPDF">导出PDF</button>
  </div>
</template>

<script>
import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'
import * as echarts from 'echarts'
import 'element-ui/lib/theme-chalk/index.css' // 确保引入了Element UI的样式

export default {
  data() {
    return {
      tableData: [
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        }
      ],

      tableDataeer: [
        {
          date: '2016-05-02',
          name: [
            { add: '数据', cs: '23' },
            { add: '数据1', cs: '23' }
          ],
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-02',
          name: [
            { add: '数据1', cs: '231' },
            { add: '数据11', cs: '231' }
          ],
          address: '上海市普陀区金沙江路 1518 弄'
        }
      ]
    }
  },
  mounted() {
    this.initChart()
  },
  methods: {
    initChart() {
      const chartDom = document.getElementById('chart')
      const myChart = echarts.init(chartDom)
      const option = {
        title: {
          text: 'Referer of a Website',
          subtext: 'Fake Data',
          left: 'center'
        },
        tooltip: {
          trigger: 'item'
        },
        legend: {
          orient: 'vertical',
          left: 'right',
          overflow: 'truncate', // 超出部分截断
          ellipsis: '...' // 显示省略号
        },
        series: [
          {
            name: 'Access From',
            type: 'pie',
            radius: '50%',
            data: [
              { value: 1048, name: 'Search Engine' },
              { value: 735, name: 'Direct' },
              { value: 580, name: 'Email' },
              { value: 484, name: 'Union Ads' },
              { value: 300, name: 'Video Ads' }
            ],
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
              }
            }
          }
        ]
      }
      myChart.setOption(option)
    },
    exportPDF() {
      const element = this.$refs.pdfContent
      html2canvas(element).then((canvas) => {
        const imgData = canvas.toDataURL('image/png')
        // eslint-disable-next-line new-cap
        const pdf = new jsPDF({
          orientation: 'portrait',
          unit: 'pt',
          format: 'a4'
        })

        const imgProps = pdf.getImageProperties(imgData)
        const margin = 20 // 设置页边距
        const pdfWidth = pdf.internal.pageSize.getWidth() - margin * 2 // 减去左右边距
        const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width // 按比例计算高度

        let position = margin // 初始Y位置(顶部边距)
        let remainingHeight = pdfHeight // 剩余需要渲染的高度

        while (remainingHeight > 0) {
          // 当前页可用的高度(减去上下边距)
          const pageHeight = pdf.internal.pageSize.getHeight() - margin

          // 计算本次渲染的高度(不能超过页面剩余高度)
          const renderHeight = Math.min(remainingHeight, pageHeight - position)

          // 添加图像部分
          pdf.addImage(
            imgData,
            'PNG',
            margin, // x位置(左边距)
            position - (remainingHeight - pdfHeight), // y位置(考虑偏移)
            pdfWidth,
            renderHeight,
            null,
            'FAST' // 使用FAST模式提高性能
          )

          remainingHeight -= renderHeight
          position += renderHeight

          // 如果还有内容未渲染,添加新页面
          if (remainingHeight > 0) {
            pdf.addPage()
            position = margin // 新页面从顶部边距开始
          }
        }

        pdf.save('chart_and_table.pdf')
      })
    }
  }
}
</script>

<style scoped>
/* 你的样式 */
</style>

主要需要处理的问题:

  1. 内容截断问题

    • 当内容超过一页时,分页逻辑可能会导致内容被截断在页面中间

    • 特别是表格行可能会被不自然地分割在两页之间

  2. 样式完整性问题

    • Element UI表格的样式可能在PDF中显示不完整

    • ECharts图表在高分辨率导出时可能模糊

  3. 性能优化

    • 对于大量数据,html2canvas渲染可能较慢

    • PDF生成过程可能阻塞UI

  4. 布局适应性

    • 固定宽度(800px)可能在不同设备上显示不一致

    • 边距控制需要更精细

相关推荐
naice4 分钟前
我对github的图片很不爽了,于是用AI写了一个图片预览插件
前端·javascript·git
天蓝色的鱼鱼8 分钟前
Element UI 2.X 主题定制完整指南:解决官方工具失效的实战方案
前端·vue.js
小奋斗16 分钟前
千量数据级别的数据统计分析渲染
前端·javascript
三小河35 分钟前
overflow:auto 滚动的问题,以及flex 布局中如何设置
前端·javascript
Hilaku39 分钟前
Token已过期,我是如何实现无感刷新Token的?
前端·javascript·面试
我是日安1 小时前
从零到一打造 Vue3 响应式系统 Day 8 - Effect:深入剖析嵌套 effect
前端·vue.js
云枫晖1 小时前
手写Promise-什么是Promise
前端·javascript
DevUI团队1 小时前
🚀 MateChat V1.8.0 震撼发布!对话卡片可视化升级,对话体验全面进化~
前端·vue.js·人工智能
一枚前端小能手1 小时前
📋 前端复制那点事 - 5个实用技巧让你的复制功能更完美
前端·javascript
好好好明天会更好1 小时前
pinia从定义到运用
前端·vue.js