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

news2024/11/20 20:20:02

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

  

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源版本管理系统的搭建一:SVN服务端安装

作者&#xff1a;私语茶馆 1.Windows搭建SVN版本管理系统 点评&#xff1a;SVN本身非常简洁易用&#xff0c;VisualSVN文档支撑非常好&#xff0c;客户端TortoiseSVN非常专业。5星好评。 1.1.SVN概要和组成 背景介绍 Svn是一个开源版本管理系统&#xff0c;由CollabNet公司…

ffmpeg 推流

参考 【windows&&linux环境下实现ffmpeg&&vlc rtsp本地视频、摄像头推流&#xff0c;VLC推拉流】 本地视频 推流 localhost 下载 mediamtx 服务器 https://github.com/bluenviron/mediamtx/releases 下载 ffmpeg https://github.com/BtbN/FFmpeg-Builds/rel…

基于vmware虚拟机中yum源的配置

1.首先需确保虚拟机中已经连接了光盘映像&#xff08;如图在虚拟机右下方从左往右第二个&#xff09; 2.在虚拟机中找到光盘映像文件&#xff08;默认在/dev的sr0&#xff09; 3.将光盘文件挂载&#xff08;挂载后才可读取&#xff09; 为方便每一次开机之后自动挂载&#xff…

jQuery 笔记13 JavaScript的好帮手

相关内容&#xff1a;下载jQuery网址、jQuery的使用、表格排序软件&#xff08;tablesorter&#xff09;、行事历软件&#xff08;FullCalendar&#xff09;、…… jQuery是一套开放性源代码的JavaScript函数库(Library)&#xff0c;jQuery是JavaScript函数库&#xff0c;简化了…

《21天学通C++》(第十二章)运算符类型与运算符重载

1.为什么要重载运算符&#xff1f; 通过重载运算符&#xff0c;可以将复杂的操作封装成简单的运算符形式&#xff0c;简化代码&#xff0c;提高可读性下面举一个简单的例子 计算两个点的坐标之和。 1.不重载运算符 #include <iostream> using namespace std; class P…

JavaScript基础(四)

逻辑运算符 && 与 : 多个条件同时满足 ΙΙ 或 : 多个条件满足一个 &#xff01; 非 : 否定某个条件 例: <script> //&多个条件同时满足&#xff0c;才返回true //任意一个为false&#xff0c;就返回false var a 10; var b 20; …

【linux】重定向

重定向 什么是重定向如何实现一个简单的重定向关于重定向的系统调用接口 注意&#xff1a;在看这篇博客之前&#xff0c;最好是要对文件在系统中是如何被打开的以及操作系统是如何管理文件有一个初步了解&#xff0c;如果不了解的话&#xff0c;可以看看这篇博客《初步认识文件…

stm32之hal库spi驱动封装(实现阻塞,中断,dma三种方式)

前言 配置功能参考rt-thread驱动代码将中断配置和dma配置单独分开管理 代码 中断管理 头文件 /** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-5-3 shchl first version*/#ifnd…

【AIGC】本地部署 ollama + open-webui

在之前的篇章《【AIGC】本地部署 ollama(gguf) 与项目整合》中我们已经使用 ollama 部署了一个基于预量化&#xff08;gguf&#xff09;的 Qwen1.5 模型&#xff0c;这个模型除了提供研发使用外&#xff0c;我还想提供给公司内部使用&#xff0c;因此还需要一个 ui 交互界面。 …

2003-2022年各省对外直接投资存量/省对外直接投资流量/省OFDI流量/省OFDI存量数据

2003-2022年各省对外直接投资存量、省对外直接投资流量、省OFDI流量、省OFDI存量数据 1、时间&#xff1a;2003-2022年 2、来源&#xff1a;对外直接投资公报 3、范围&#xff1a;31省 4、指标&#xff1a;省对外直接投资流量/OFDI流量、省对外直接投资存量/OFDI存量 5、指…

OpenCV(三)—— 车牌筛选

本篇文章要介绍如何对从候选车牌中选出最终进行字符识别的车牌。 无论是通过 Sobel 还是 HSV 计算出的候选车牌都可能不止一个&#xff0c;需要对它们进行评分&#xff0c;选出最终要进行识别的车牌。这个过程中会用到两个理论知识&#xff1a;支持向量机和 HOG 特征。 1、支…

爬虫自动化之drissionpage实现随时切换代理ip

目录 一、视频二、dp首次启动设置代理三、dp利用插件随时切换代理一、视频 视频直接点击学习SwitchyOmega插件使用其它二、dp首次启动设置代理 from DrissionPage import ChromiumPage, ChromiumOptions from loguru

MySQL与金蝶云星空对接集成执行查询语句-v2打通销售退货新增V1

MySQL与金蝶云星空对接集成执行查询语句-v2打通销售退货新增V1 数据源系统:MySQL mysql是一个关系数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;所谓的关系型数据库&#xff0c;是建立在关系模型基础上的数据库&#xff0c;借助于集合代数等数学概念和方法来处理数…

深度解析 Spring 源码:探寻Bean的生命周期

文章目录 一、 Bean生命周期概述二、Bean生命周期流程图三、Bean生命周期验证3.1 代码案例3.2 执行结果 四、Bean生命周期源码4.1 setBeanName()4.2 setBeanFactory()4.3 setApplicationContext()4.4 postProcessBeforeInitialization()4.5 afterPropertiesSet()4.6 postProces…

npm安装依赖报错解决办法

项目场景&#xff1a; 安装gitee上的开源vue3TS项目&#xff0c;npm安装依赖报错 问题描述 克隆项目到VSCode之后&#xff0c;使用npm install安装依赖&#xff0c;报错 npm install npm ERR! code ENOENT npm ERR! syscall open npm ERR! path Y:\WebStudyBlog\MovieWeb/p…

【Linux】学习笔记

文章目录 [toc]第一章&#xff1a;基础篇01|课程介绍02|内容综述03|什么是Linux04|Linux的内核版本及常见发行版内核版本发行版本Red Hat Enterprise LinuxFedoraCentOSDebianUbuntu 05|安装VirtualBox虚拟机VirtualBox下载url 06|在虚拟机中安装Linux系统Linux安装镜像下载 07…

基于OpenCv的图像傅里叶变换

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

【C++并发编程】(四)条件变量

文章目录 &#xff08;四&#xff09;条件变量 &#xff08;四&#xff09;条件变量 条件变量&#xff08;Condition Variable&#xff09;用于线程间的同步&#xff0c;允许一个或多个线程在特定条件不满足时等待&#xff0c;并在条件满足时被其他线程唤醒。C标准库中提供了的…

D3CTF2024

文章目录 前言notewrite_flag_where【复现】D3BabyEscapePwnShell 前言 本次比赛笔者就做出两道简单题&#xff0c;但队里师傅太快了&#xff0c;所以也没我啥事。然后 WebPwn 那题命令行通了&#xff0c;但是浏览器不会调试&#xff0c;然后就简单记录一下。 note 只开了 N…

【热门话题】如何构建具有高度扩展性的系统

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 如何构建具有高度扩展性的系统引言一、理解扩展性1.1 扩展性的定义1.2 扩展性的…