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

多个表格需要,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>

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/586193.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FFmpeg开发笔记(二十三)使用OBS Studio开启RTMP直播推流

OBS是一个开源的直播录制软件&#xff0c;英文全称叫做Open Broadcaster Software&#xff0c;广泛用于视频录制、实时直播等领域。OBS不但开源&#xff0c;而且跨平台&#xff0c;兼容Windows、Mac OS、Linux等操作系统。 OBS的官网是https://obsproject.com/&#xff0c;录制…

STM32利用硬件I2C读取MPU6050陀螺仪数据

有了前面的基本配置&#xff0c;这节读取MPU6050的数据还算是简单&#xff0c;主要就是初始化时给MPU6050一些配置&#xff0c;取消睡眠模式&#xff0c;MPU6050开机是默认睡眠模式的&#xff0c;读写无效&#xff0c;所以上来就要先更改配置&#xff1a; MPU6050寄存器初始化…

mongodb卸载(win)

关闭服务 &#xff08;或者cmd卸载服务&#xff1a;&#xff09; net stop 服务名称卸载应用 至此&#xff0c;卸载完成&#xff01;

微隔离实施五步法,让安全防护转起来

前言 零信任的最核心原则→最小权限 安全的第一性原理→预防 零信任的最佳实践→微隔离 “零信任”这个术语的正式出现&#xff0c;公认是在2010年由Forrester分析师John Kindervag最早提出。时至今日&#xff0c;“零信任”俨然已成安全领域最热门的词汇&#xff0c;做安全…

实验报告5-Spring MVC实现页面

实验报告5-SpringMVC实现页面 一、需求分析 使用Spring MVC框架&#xff0c;从视图、控制器和模型三方面实验动态页面。模拟实现用户登录&#xff0c;模拟的用户名密码以模型属性方式存放在Spring容器中&#xff0c;控制器相应用户请求并映射参数&#xff0c;页面收集用户数据或…

设计模式-01 设计模式单例模式

设计模式-01 设计模式单例模式 目录 设计模式-01 设计模式单例模式 1定义 2.内涵 3.使用示例 4.具体代码使用实践 5.注意事项 6.最佳实践 7.总结 1 定义 单例模式是一种设计模式&#xff0c;它确保一个类只能被实例化一次。它通过在类内部创建类的唯一实例并提供一个全…

uniapp + uView动态表单校验

项目需求&#xff1a;动态循环表单&#xff0c;并实现动态表单校验 页面&#xff1a; <u--form label-position"top" :model"tmForm" ref"tmForm" label-width"0px" :rulesrules><div v-for"(element, index) in tmForm…

(详细整理!!!!)Tensorflow与Keras、Python版本对应关系!!!

小伙伴们大家好&#xff0c;不知道大家有没有被tensorflow框架困扰过 今天我就给大家整理一下tensorflow和keras、python版本的对应关系 大家这些都可以在官网找到&#xff0c;下面我把官网的连接给大家放在这里&#xff1a;在 Windows 环境中从源代码构建 | TensorFlow (g…

搭建大型分布式服务(三十七)SpringBoot 整合多个kafka数据源-取消限定符

系列文章目录 文章目录 系列文章目录前言一、本文要点二、开发环境三、原项目四、修改项目五、测试一下五、小结 前言 本插件稳定运行上百个kafka项目&#xff0c;每天处理上亿级的数据的精简小插件&#xff0c;快速上手。 <dependency><groupId>io.github.vipjo…

基于 React 的图形验证码插件

react-captcha-code NPM 地址 &#xff1a; react-captcha-code - npm npm install react-captcha-code --save 如下我自己的封装&#xff1a; import Captcha from "react-captcha-code";type CaptchaType {captchaChange: (captchaInfo: string) > void;code…

前端发起网络请求的几种常见方式(XMLHttpRequest、FetchApi、jQueryAjax、Axios)

摘要 前端发起网络请求的几种常见方式包括&#xff1a; XMLHttpRequest (XHR)&#xff1a; 这是最传统和最常见的方式之一。它允许客户端与服务器进行异步通信。XHR API 提供了一个在后台发送 HTTP 请求和接收响应的机制&#xff0c;使得页面能够在不刷新的情况下更新部分内容…

Flutter笔记:Widgets Easier组件库(2)阴影盒子

Flutter笔记 Widgets Easier组件库&#xff08;2&#xff09;&#xff1a;阴影盒子 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress o…

Python中的动态数据可视化Bokeh库实战

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python 中的动态数据可视化Bokeh库实战 在数据科学和可视化领域&#xff0c;动态数据可视化…

windows下安装onlyoffice

文章目录 1、 安装ErLang2、 安装rabbitmq3、 安装postgresql4、 安装onlyoffice(社区版) 1、 安装ErLang 下载地址&#xff1a;https://erlang.org/download/otp_win64_24.2.exe opt_wind64_24.2.exe 直接运行&#xff0c;一步一步安装 2、 安装rabbitmq 下载地址&#xf…

【笔记】Simulink与Workbench交互+自定义m函数封装为Simulink模块

以如下三角函数为例&#xff0c;说明建模方法 ya*sin(b*2*pi*uc);0.总模型总代码 总模型 总代码&#xff1a; clc clear close allt_all10; a10; b1; c0;%pi/2; delta_t0.01; simOutsim(test240430); out_tsimOut.tout; out_y1simOut.yout{1}.Values; out_y2simOut.yout{2}.…

C++-10

1.C一个程序&#xff0c;实现两个类&#xff0c;分别存放输入的字符串中的数字和字母&#xff0c;并按各自的顺序排列&#xff0c; 类中实现-一个dump函数&#xff0c;调C用后输出类中当前存放的字符串结果。 例如&#xff0c;输入1u4y2a3d,输出:存放字母的类&#xff0c;输出a…

机器人正反向运动学(FK和IK)

绕第一个顶点可以沿Z轴转动&#xff0c;角度用alpha表示 绕第二个点沿X轴转动&#xff0c;角度为Beta 第三个点沿X轴转动&#xff0c;记作gama 这三个点构成姿态&#xff08;pose&#xff09; 我们记第一个点为P0&#xff0c;画出它的本地坐标系&#xff0c;和世界坐标系一样红…

无人机+三维建模:倾斜摄影技术详解

无人机倾斜摄影测量技术是一项高新技术&#xff0c;近年来在国际摄影测量领域得到了快速发展。这种技术通过从一个垂直和四个倾斜的五个不同视角同步采集影像&#xff0c;从而获取到丰富的建筑物顶面及侧视的高分辨率纹理。这种技术不仅能够真实地反映地物情况&#xff0c;还能…

设计模式 --6组合模式

文章目录 组合模式应用场景组合模式概念组合模式结构图透明方式和安全方式什么时候使用组合模式公司管理系统使用 组合模式来构架组合模式的好处 组合模式应用场景 整体和部分可以被一致性对待 比如人力资源部 财务部的管理功能可以复用于分公司的功能 可以引入一种 树状的结构…

【webrtc】MessageHandler 2: 基于线程的消息处理:以PeerConnectionClient为例

PeerConnectionClient 前一篇 nullaudiopoller 并么有场景线程,而是就是在当前线程直接执行的, PeerConnectionClient 作为一个独立的客户端,默认的是主线程。 PeerConnectionClient 同时维护客户端的信令状态,并且通过OnMessage实现MessageHandler 消息处理。 目前只处理一…