vue3 jspdf,element table 导出excel、pdf,横板竖版分页

发布于:2024-05-01 ⋅ 阅读:(33) ⋅ 点赞:(0)

多个表格需要,pdf需要的格式与原本展示的表格样式不同

1.创建一个新的表格,设置pdf需要的样式,用vue的h函数放入dom中

2.excel用xlxs插件直接传入新建el-table的dom,直接导出

3.pdf导出类似excel黑色边框白底黑字的文件,把el-table改成需要的样式,

由于table内部的表格是由td,tr绘制的所以表头和表格本身必须使用插槽写div给固定的表格宽度和高度配合

 :row-style="rowStyle"

:cell-style="cellStyle"

:header-cell-style="headerCellStyle"

4.导pdf使用jspdf插件,只能接受图片格式(base64/png、jpg)等,使用html2Canvas先把dom转成canvas在转成图片

5.pdf文件的尺寸和分页需要根据需求设置,主要方法是

创建pdf文件对象
 let pdf = new jsPDF('p', 'mm', 'a4'); 
为pdf页添加图片内容
pdf.addImage(
          testImage,
          'JPEG',
          10,
          10,
          190,
          Math.min(a4h, (190 * page.height) / page.width),
        );
新增一页
pdf.addPage();

demo

exportPDFExcel.js

导出方法调出弹窗,调用addTable方法dom创建成功后处理导出事件

import { ElMessageBox, ElButton, ElLoading, ElTable } from 'element-plus'
import { h, nextTick } from 'vue'
import { request } from "@/utils/request";
import Menu from "./creatTable.js";
import { saveAs } from "file-saver";
import XLSX from "xlsx";
import { removeTable } from "./creatTable";
import html2Canvas from 'html2canvas';
import jsPDF from 'jspdf';
let fileName = ''
let fileType = ''
let mesBox = null
let loading = null
//导选择创口,pdfexcel
export function exportMessageBox(params, name, columns) {
 ElMessageBox({
    title: '请选择导出格式',
    message: h('p', null, [
      h('div', {
        class: 'el-button el-button--primary el-button--default', innerHTML: 'Excel', onClick: () => {
          getData(params, name, columns, 'xlsx')
        }
      }),
      h('div', {
        class: 'el-button el-button--primary el-button--default', innerHTML: 'PDF', onClick: () => {
          getData(params, name, columns, 'pdf')
        }
      })
    ]),
    'showConfirmButton': false
  })

}
function getData(params, name, columns, type) {
//关闭弹窗,打开loading
  mesBox = document.querySelector(".el-message-box__headerbtn");
  mesBox.click();
  loading = ElLoading.service({
    text: "正在下载数据,请稍候",
    background: "rgba(0, 0, 0, 0.7)",
  });

  fileName = name
  fileType = type
 //业务操作,调接口抽数据
  request.get(params.url, params).then((response) => {
    if (response.code === 200) {
     
      let list = response.rows;
//创建table,传递列和数据组
      Menu.addTable(list, columns)


    }
  });
}
export function downFile(params) {
//构建文件名
  const currentDate = new Date();

  const year = currentDate.getFullYear();
  const month = String(currentDate.getMonth() + 1).padStart(2, "0");
  const day = String(currentDate.getDate()).padStart(2, "0");
  const hours = String(currentDate.getHours()).padStart(2, "0");
  const minutes = String(currentDate.getMinutes()).padStart(2, "0");
  const seconds = String(currentDate.getSeconds()).padStart(2, "0");
  const formattedDate = `${year}_${month}_${day}_${hours}_${minutes}_${seconds}`;
  const txt = `${fileName}${formattedDate}.${fileType}`

  nextTick(() => {
//获取到dom
    const table = document.querySelector("#table_export_content_one")
    if (fileType === 'xlsx') {
//导出excel,直接传dom给XLSX用其方法
      const workbook = XLSX.utils.table_to_book(
        table,
        {
          raw: true, //有的是日期、小数等格式,直接乱码#。所以这里直接保留原始字符串
        }
      );
      const wbout = XLSX.write(workbook, {
        bookType: "xlsx",
        bookSST: true,
        type: "array",
      });
      saveAs(
        new Blob([wbout], {
          type: "application/octet-stream",
        }),
        txt
      );
      removeTable()
      loading.close()
    }
    else {
      downPDF()

    }



  });
}
//导出pdf
function downPDF() {
  const table = document.querySelector("#table_export_content_one")
  let title = fileName
//表格整体转canvas
  html2Canvas(table, {
    removeContainer: true,
    useCORS: true,
  }).then((canvas) => {
    let pdf = new jsPDF('p', 'mm', 'a4'); //A4纸,纵向
//a4w和a4h在列少的情况可以直接配210*297,列多横板分页需要配成表格宽度*一页需要放的表格数,高度类比
    let ctx = canvas.getContext('2d'),
      a4w = 154 * 8,
      a4h = 25 * 100, //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
      renderedWidth = 0
    let kss = true
    while (renderedWidth <= canvas.width) {

      let renderedHeight = 0

      while (renderedHeight <= canvas.height) {
        let page = document.createElement('canvas');
        page.width = Math.min(a4w, canvas.width - renderedWidth);
        page.height = Math.min(a4h, canvas.height - renderedHeight); //可能内容不足一页
     //getImage获取一页的选区转成图片,参数为x,y,width,height
        page
          .getContext('2d')
          .putImageData(
            ctx.getImageData(
              renderedWidth,
              renderedHeight,
              Math.min(a4w, canvas.width - renderedWidth),
              Math.min(a4h, canvas.height - renderedHeight),
            ),
            0,
            0,
          );
        const testImage = page.toDataURL('image/jpeg', 1.0)
if(!kss){
  const allImage = canvas.toDataURL('image/jpeg', 1.0)
 const a = document.createElement("a");
        a.download =  '0123456.PNG';
        a.href = allImage;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        kss=true
}
//将获取的该页image加入到pdf中
        pdf.addImage(
          testImage,
          'JPEG',
          10,
          10,
          190,
          Math.min(a4h, (190 * page.height) / page.width),
        ); //添加图像到页面,保留10mm边距
        renderedHeight += a4h;
      if (renderedHeight < canvas.height) {
        pdf.addPage(); //如果后面还有内容,添加一个空页
      }  
      }
      renderedWidth += a4w;
        if (renderedWidth < canvas.width) {
          pdf.addPage(); //如果后面还有内容,添加一个空页
        }
    }

    pdf.save(title + '.pdf');
//移除临时创建的table,
    removeTable()
    loading.close()
  })
}

function formatJson(filterVal, list) {
  return list.map((v) =>
    filterVal.map((j) => {
      // 进行日期格式化
      const arr = j.split(".");
      if (arr.length === 1) {
        return v[j];
      } else if (arr.length === 2 && eval("v." + arr[0])) {
        return eval("v." + j);
      } else if (
        arr.length === 3 &&
        eval("v." + arr[0]) &&
        eval("v." + arr[0] + "." + arr[1])
      ) {
        return eval("v." + j);
      }
      return "";
    })
  );
}

creatTable.js

创建table方法和移除table方法

import { createVNode, render ,h, nextTick} from "vue";
import tableElement from "./index.vue";

import {downFile} from './exportPDFExcel'

//      定义一个div容器
const div = document.createElement("div");

document.body.appendChild(div);
export default {
  addTable(list, columnsProp,) {
    const vnode = createVNode(tableElement, { list, columnsProp });
    render(vnode, div);
    nextTick(()=>{
      downFile()

    })
  },
};
export const removeTable = function () {
  render(null, div);
};

index.vue

虚拟构建的table的dom内容,和参数处理

<template>
  <div class="export_box_table">
  <div class="export_table">
    <el-table
      :row-style="rowStyle"
      :cell-style="cellStyle"
      :header-cell-style="headerCellStyle"
      id="table_export_content_one"
      :data="test"
      isShowDynamicColumn
    >
      <el-table-column
        v-for="item in columns"
        :label="item.label"
        :prop="item.prop"
      >
        <template #header="scope">
          <div :style="{ width: cellHeight + 'px' }">
            {{ item.label }}
          </div>
        </template>
        <template #default="scope">
       
          <div
            :style="{
              'background-color': getStyle1(scope.row, item),
              width: cellHeight + 'px',
              color: '#000',
            }"
          >
          44444
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>
  </div>
</template>
  
  <script setup>
import dciTableColumn from "@/views/admin/dci/components/dciTableColumn.vue";
import { ElTable, ElTableColumn } from "element-plus";
import { computed } from "vue";

const { proxy } = getCurrentInstance();
const columns = ref([]);
const cellHeight = ref(150);
const tableWidth = computed(() => {
  return (cellHeight.value+26) * (columns.value.length) + "px";
});
//测试数据
let testObj = 
  {
    createBy: null,
    createTime: "2023-11-20 16:29:57",
    instPowerT: 0,
    instPowerMw: 0,
    instCoal: 0,
    instGas: 0,
    instWater: 0,
    instElec: 0,
    instHeat: 301.73,

  }
let test = new Array(200).fill(testObj);
//测试结束
defineProps({
  list: {
    type: Array,
    default() {
      return [];
    },
  },
  columnsProp: {
    type: Array,
    default() {
      return [];
    },
  },
});

initTable();
function initTable() {
  columns.value = [];

  proxy.columnsProp.forEach((item, index) => {
    if (item.props) {
      initItem(item.props);
      columns.value.push(item.props);
    }
  });
}

function rowStyle() {
  return {
    // "background-color": "rgba(2,5,2,0.2)",
    // "background-color": "rgba(7,29,68,1)",
    color: "#000",
  };
}
function cellStyle() {
  let hei = "2px";
  let style = {
    border: "1px solid #000",
    // "background-color": "rgba(7,29,68,1)",
    "background-color": "#fff",
    padding: "0px",
    height: hei,
    "line-height": hei,
  };
  return style;
}
function headerCellStyle() {
  return {
    "background-color": "#fff!important",
    width: "250px",
    border: "1px solid #000",
    color: "#000",
    height: "32px!important",
    "font-size": "14px",
    padding: "0px",
    "line-height": "32px",
  };
}


function initItem(item) {
  item.magnification = item.magnification ? item.magnification : 1;
  item.suffix = item.suffix ? item.suffix : "";
  item.color = item.color ? item.color : "";
  item.type = item.type ? item.type : "";
  item.tooltip = item.tooltip ? item.tooltip : "";
  item.chuhui = item.chuhui ? item.chuhui : "";
  item.ziduanName = item.ziduanName ? item.ziduanName : "";
  item.ziduanValue = item.ziduanValue ? item.ziduanValue : "";
  item.ziduanColor = item.ziduanColor ? item.ziduanColor : "";
  item.isPhone = item.isPhone ? item.isPhone : false;
  item.time = item.time ? item.time : false;
  item.fixedNumber = item.fixedNumber ? item.fixedNumber : 1;
  item.export = item.export ? item.export : false;
}

</script>
  
  <style scoped>
  .export_box_table{
    width: 800px;
    overflow: auto;
 
    /* position: fixed; */
    height: 500px;
    /* z-index: 500; */
    /* top: 0px; */
    background-color: rgb(0, 255, 179);
  }
.export_table {
  width: fit-content;
  height: 500px;
  background-color: red;
  /* position: absolute;
  top: 0px;
  left: 0px; */

  overflow: auto;
}
#table_export_content_one {
  width: v-bind(tableWidth);
}
</style>
<style lang="scss" scoped>
.column_visible {
  position: absolute;
  z-index: 9;
  left: 100px;
  top: -0px;
}
</style>
<style>
.hover_row_pointer:hover {
  cursor: pointer;
}
</style>

  


网站公告

今日签到

点亮在社区的每一天
去签到