将图表和表格导出为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)可能在不同设备上显示不一致

    • 边距控制需要更精细

相关推荐
BillKu22 分钟前
Vue3 + TypeScript + Element Plus + el-input 输入框列表按回车聚焦到下一行
前端·javascript·typescript
阿古达木26 分钟前
沉浸式改 bug,步步深入
前端·javascript·github
夏沫mds26 分钟前
Hyperledger Fabric食品溯源
运维·vue.js·go·vue·区块链·gin·fabric
小泡芙丫27 分钟前
JavaScript 的 Promise:一场关于相亲、结婚与生子的异步人生大戏
javascript
Humbunklung1 小时前
DeepSeek辅助写一个Vue3页面
前端·javascript·vue.js
二闹2 小时前
🚀 JavaScript性能优化实战:让你的JS代码从拖拉机变超跑!🏎️💨
前端·javascript·性能优化
jstopo网站2 小时前
可拖拽配置3d地下停车场大屏
前端·javascript
烛阴3 小时前
💻 从0到1掌握CSS选择器:精准元素定位的终极指南
前端·javascript·css
实习生小黄3 小时前
使用psd.js将psd路径转成svg格式
前端·javascript·svg
Hilaku3 小时前
尤雨溪都没告诉你的 setup() 技巧
前端·javascript·vue.js