pdfMake,xlsx-js-style,elementTable表格导出大量数据的pdf和xslx表格

 使用渲染dom传递给xlsx或将dom转canvas在传给jspdf数据量大都会造成页面负载过大

所以导pdf和xlsx都使用数据传递给pdfMake,xlsx-js-style,pdf涉及分页与合并单元格

 一.pdf

npm并引入pdfMake和其字体包(记录时使用版本0.2.10

import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";

 官网地址pdfmake

pdfMake支持表格和列表等传递数据类型导出pdf,支持水印与合并行列单元格,支持字体颜色和简单样式设置

1.引入中文字体包

pdfMake自带的roboto字体不支持中文,所以需要自己下载一个支持中文的ttf文件,这里使用

SourceHanSansCN-Normal.ttf,网上下载该文件资源,在node_modules的pdfMake包中新建examples

文件夹,在examples中新建一个fonts文件夹,将需要的字体包复制进去。

在pdfMake的目录下打开控制台或者cmd等命令行运行命令,pdfmake会构建字体的编码到pdfmake下的/build/vfs_fonts.js中,这个文件应该包含四种roboto字体

node build-vfs.js "./examples/fonts"

2.引入字体出现错误

pdfmake Font 'Roboto' in style 'bold' is not defined in the font section of或

File 'Roboto-Regular.ttf' not found in virtual file system,等问题

pdfmake Font ‘Roboto‘ in style ‘bold‘ is not defined in the font section of或File ‘Roboto-Regular.t-CSDN博客

3.使用pdfMake的数据格式

contect =	{
			style: 'tableExample',
			color: '#444',
			table: {
//每行宽度
				widths: [200, 'auto', 'auto'],
//表头的行数,设置为表头分页时会携带
				headerRows: 2,
				// keepWithHeaderRows: 1,
//table的数据,合并Colspan ,rowspan
				body: [
					[{text: 'Header with Colspan = 2', style: 'tableHeader', colSpan: 2, alignment: 'center'}, {}, {text: 'Header 3', style: 'tableHeader', alignment: 'center'}],
					[{text: 'Header 1', style: 'tableHeader', alignment: 'center'}, {text: 'Header 2', style: 'tableHeader', alignment: 'center'}, {text: 'Header 3', style: 'tableHeader', alignment: 'center'}],
					['Sample value 1', 'Sample value 2', 'Sample value 3'],
					[{rowSpan: 3, text: 'rowSpan set to 3\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor'}, 'Sample value 2', 'Sample value 3'],
					['', 'Sample value 2', 'Sample value 3'],
					['Sample value 1', 'Sample value 2', 'Sample value 3'],
					['Sample value 1', {colSpan: 2, rowSpan: 2, text: 'Both:\nrowSpan and colSpan\ncan be defined at the same time'}, ''],
					['Sample value 1', '', ''],
				]
			}
		},
 let pdfMakeData = {
    // watermark: { text: '乐恒', font: 'SourceHanSansCN' } || '',
    pageSize: pageSize,
    // pageOrientation: 'portrait',
    pageMargins: [
      cardLeft,
      cardTop,
      cardLeft,
      cardTop,
    ],
    content: content,
//简单的样式
    styles: {
      tableExample: {
        margin: [0, 5, 0, 15],
        font: 'SourceHanSansCN',
        color: 'black',
      },
    },
    defaultStyle: {
      defaultStyle: {
        font: 'SourceHanSansCN'
      },
    }
  }
//业务逻辑结束,根据需要构建pdfMake需要的content
//添加vfs字体
  pdfMake.vfs = pdfFonts;
//添加字体对象,Roboto是必须添加的否则报错,剩余添加需要的字体这里是SourceHanSansCN
  pdfMake.fonts = {
    Roboto: {
      normal: 'Roboto-Regular.ttf',
      bold: 'Roboto-Medium.ttf',
      italics: 'Roboto-Italic.ttf',
      bolditalics: 'Roboto-MediumItalic.ttf'
    },
    SourceHanSansCN: {
      normal: 'SourceHanSansCN-Normal.ttf',
      bold: 'SourceHanSansCN-Normal.ttf',
      italics: 'SourceHanSansCN-Normal.ttf',
      bolditalics: 'SourceHanSansCN-Normal.ttf'
    }
  };
//下载
  pdfMake.createPdf(pdfMakeData).download(getFileName());

 4.使用pdfMake下载

function downPDF({ dataList, labelList, spanObj }) {
//设置一些活参数有用的是oneRowNum每页需要多少列,oneCellWidth每个单元格宽度,纸张型号宽高
  let cardTop = 10, cardLeft = 7, textLeft = 9, textTop = 14, oneColumnNum = 35, oneRowNum = 7, oneCellWidth = 73.7, oneCellHeight = 8, oneStrLen = 5, pdfWidth = 203, pdfHeight = 290, strLen = 8, pageSize = 'A4'
//我的业务逻辑实现开始(分页,合并单元格
  let startIndex = 0, endIndex = oneRowNum
  let content = []
  let columnPages = Math.ceil(dataList.length / oneRowNum) + 1
  for (let i = 1; i < columnPages; i++) {
    let currentColumnData = dataList.slice((i - 1) * oneRowNum, i * oneRowNum)
    let currentLabelData = labelList.slice((i - 1) * oneRowNum, i * oneRowNum)
    let ownObj = {
      table: {
        headerRows:spanObj.rowIndex[1],
        widths: new Array(currentLabelData.length).fill(oneCellWidth),
        body: [
          // [{text: 'Header 1'}, {text: 'Header 2', style: 'tableHeader'}, {text: 'Header 3', style: 'tableHeader'}],
          // ['Sample value 1', 'Sample value 2', 'Sample value 3'],

        ],
      },
      style: 'tableExample'
    }
    let headerArr = []
    currentLabelData.forEach((item) => {
      headerArr.push({ text: item })
    })
    let columnArr = new Array()
    currentColumnData.forEach((item, index) => {

      item.forEach((cItem, cIndex) => {
        columnArr[cIndex] = columnArr[cIndex] || []
        columnArr[cIndex].push(cItem)
      })
    })


    if (i === 1) {
      spanObj.columnIndex
        .forEach((item, index) => {
          for (let cindex = 0; cindex < columnArr.length; cindex++) {
            const cItem = columnArr[cindex];

            let cChild = cItem[item]
            if (cChild) {
              let repeatIndex = columnArr.filter((fItem) => {
                return fItem[item] === cChild
              }).length
              cItem[item] = { text: cChild, rowSpan: repeatIndex }
              index = repeatIndex + index - 1
            }

          }
        })
    }
    columnArr.unshift(headerArr)
    if (spanObj.rowIndex[0].length !== 0) {
      let rowHead = []
      let endLen = i + 1 === columnPages ? (dataList.length - (i - 1) * oneRowNum) : oneRowNum
      for (let keyIndex = 0; keyIndex < endLen; keyIndex++) {
        let rowCurrent = (i - 1) * oneRowNum + keyIndex
        let rowEnd = 0

        for (const key in spanObj.rowIndex[0]) {
          let children = spanObj.rowIndex[0][key]
          rowEnd = rowEnd + children.length
          if (rowEnd > rowCurrent) {
            let obj = { text: key }
            rowHead.push(obj)

            break;
          }
        }
      }

      for (let index = 0; index < rowHead.length; index++) {
        const cItem = rowHead[index];
        let repeatIndex = rowHead.filter((fItem) => {
          return fItem.text === cItem.text
        }).length
        rowHead[index].colSpan = repeatIndex
        index = repeatIndex + index - 1

      }

      columnArr.unshift(rowHead)
    }

    ownObj.table.body = columnArr
    content.push(ownObj)
  }
  console.log('content', JSON.parse(JSON.stringify(content)))
//业务逻辑结束,根据需要构建pdfMake需要的content
//添加vfs字体
  pdfMake.vfs = pdfFonts;
//添加字体对象,Roboto是必须添加的否则报错,剩余添加需要的字体这里是SourceHanSansCN
  pdfMake.fonts = {
    Roboto: {
      normal: 'Roboto-Regular.ttf',
      bold: 'Roboto-Medium.ttf',
      italics: 'Roboto-Italic.ttf',
      bolditalics: 'Roboto-MediumItalic.ttf'
    },
    SourceHanSansCN: {
      normal: 'SourceHanSansCN-Normal.ttf',
      bold: 'SourceHanSansCN-Normal.ttf',
      italics: 'SourceHanSansCN-Normal.ttf',
      bolditalics: 'SourceHanSansCN-Normal.ttf'
    }
  };
//创建打印数据对象
  let pdfMakeData = {
    // watermark: { text: '乐恒', font: 'SourceHanSansCN' } || '',
    pageSize: pageSize,
    // pageOrientation: 'portrait',
    pageMargins: [
      cardLeft,
      cardTop,
      cardLeft,
      cardTop,
    ],
    content: content,
//简单的样式
    styles: {
      tableExample: {
        margin: [0, 5, 0, 15],
        font: 'SourceHanSansCN',
        color: 'black',
      },
    },
    defaultStyle: {
      defaultStyle: {
        font: 'SourceHanSansCN'
      },
    }
  }

//下载
  pdfMake.createPdf(pdfMakeData).download(getFileName());
}

GitHub - bpampuch/pdfmake: Client/server side PDF printing in pure JavaScript

二.xlsx

1.npm下载并引入xlsx-js-style,它比xlsx支持自定义表格style,即用数据和属性可以构建xlsx的下载不传dom只操作数据

import XLSX from "xlsx-js-style";

2.下载函数,整理获取到的table数据,根据需求填充,需求只涉及二级表头的合并行与前几列的合并,并非整个表格合并

//表格数据数据,表头数据数组,合并行列数组
function downXlsx({ dataList, labelList, spanObj }) {
console.log(dataList, labelList, spanObj)
//添加合并列的单元格
  let mergesArr = []
  spanObj.columnIndex
    .forEach((item, index) => {
      for (let cindex = 0; cindex < dataList.length; cindex++) {
        const cItem = dataList[cindex];
        let cChild = cItem[item]
        if (cChild) {
          let repeatIndex = dataList.filter((fItem) => {
            return fItem[item] === cChild
          }).length
          mergesArr.push({ s: { r: cindex + 1, c: item }, e: { r: cindex + repeatIndex, c: item } })
          cindex = repeatIndex + cindex - 1
        }
      }
    })
//添加表头为第一列
  dataList.unshift(labelList)
//添加合并列的单元格(二级表头
  if (spanObj.rowIndex[0].length !== 0) {
    let rowHead = []
    for (let keyIndex = 0; keyIndex < labelList.length; keyIndex++) {
      let rowEnd = 0
      for (const key in spanObj.rowIndex[0]) {
        let children = spanObj.rowIndex[0][key]
        rowEnd = rowEnd + children.length
        if (rowEnd > keyIndex) { 
          rowHead.push(key)
          break;
        }
      }
    }
    for (let index = 0; index < rowHead.length; index++) {
      const cItem = rowHead[index];
      let repeatIndex = rowHead.filter((fItem) => {
        return fItem === cItem
      }).length
      mergesArr.push({ s: { r: 0, c: index }, e: { r: 0, c: index + repeatIndex-1 } })
      index = repeatIndex + index - 1
    }
    dataList.unshift(rowHead)
  }
//创建xlsx,下载
  const wb = XLSX.utils.book_new();
  const ws = XLSX.utils.json_to_sheet(dataList, {
    skipHeader: true,
  });

  ws["!merges"] = mergesArr;
  XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
  XLSX.writeFile(wb, getFileName());
}

spanObj的数据格式

//datalist每个元素的数据是table的行数据
datalist:[[],[],[]]
labelList:["名称","事件","ey位m","温度℃""]
spanObj :{
//多级表头,一级表头属性下的二级表头内容
    "rowIndex": [
        {
            "基础信息": [
                {
                    "label": "名称",
                    "prop": "MingCheng",
                    "width": "150",
                    "click": "rezhan"
                },
                {
                    "label": "事件",
                    "prop": "事件",
                    "width": "150",
                    "click": "rezhan"
                },
            ],

            "xx数据": [
                {
                    "label": "ey位m",
                    "prop": "shuiXiangYeWei",
                    "width": "100",
                    "fixed": 1
                },
            
            ],
            "其他数据": [
                {
                    "label": "温度℃",
                    "prop": "shiWaiWenDu",
                    "width": "110",
                    "fixed": 1
                },
          
            ]
        },
        2
    ],
//第0列需要合并,合并相同内容
    "columnIndex": [0]
}

 html简单demo,fonts里有字体运行index即可

pdfxlsx: 不操作dom导出pdf xlsxxlsx-js-style pdfmake

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

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

相关文章

【系统架构师】-案例篇(十二)MQTT、边缘计算与缓存一致性

1、MQTT是一个基于物联网的传输协议&#xff0c;用于轻量级的订阅发布的消息传输。旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。 开放消息协议&#xff0c;简单易实现发布订阅模式&#xff0c;一对多消息发布基于TCP/IP网络连接,提供有序&#xff0c;无损…

【Vue开发】基于SSM++jsp的精品酒销售管理系统【源码+lw+部署文档+讲解】

目录 第一章 绪 论 第二章 关键技术的研究 2.1 JSP技术介绍 2.2 JAVA简介 2.3 ECLIPSE 开发环境 2.4 Tomcat服务器 2.5 MySQL数据库 第三章 系统分析 3.1 系统设计目标 3.2 系统可行性分析 3.3 系统功能分析和描述 3.4系统UML用例分析 3.4.1管理员用例 3.4.2用户用例 3.5系统流…

提升效率! 宏集助力客户实现仓储和物流系统的智能化改造

前言 在现代物流与仓储管理领域&#xff0c;自动存储和检索系统已日益普及&#xff0c;堆垛机和物流小车组合的仓储系统成为高效、精确存储和取货货物的关键。随着技术的进步&#xff0c;堆垛机的定位技术也在不断优化。传统堆垛机采用机械装置和导轨上的光电开关进行定位&…

成都欣丰洪泰文化传媒有限公司电商服务新典范

在数字化浪潮席卷而来的今天&#xff0c;电商行业作为新时代商业发展的重要引擎&#xff0c;正以其独特的魅力和无限潜力&#xff0c;吸引着越来越多的企业和个人投身其中。在这个充满机遇与挑战的领域中&#xff0c;成都欣丰洪泰文化传媒有限公司以其专业的电商服务&#xff0…

CTF如何学习?

CTF如何学习&#xff1f;打CTF有什么用 CTF本身有几个常见的领域 MISC WEB [逆向 密码学](https://www.zhihu.com/search?q逆向 密码学&search_sourceEntity&hybrid_search_sourceEntity&hybrid_search_extra{“sourceType”%3A"answer"%2C"sourc…

yolov8添加FPPI评价指标

这里写自定义目录标题 yolov8 中FPPI实现测试中调用 效果结语 续yolov7添加FPPI评价指标 。之前在yolov7中增加了fppi指标&#xff0c;有不少网友问有没有yolov8中增加&#xff0c;最近没有做算法训练&#xff0c;也一直没时间弄。这几天晚上抽了点时间&#xff0c;弄了一下。不…

Vue3 - 项目配置多环境配置文件

最常见的多环境配置,就是开发环境配置,和生产环境配置(也就是上线的配置),很多情况下我们开发环境下的域名,和一些配置项,和我们生产模式下的不同,这个时候就需要我们进行多环境配置,不然每次发版都要改一波数据多麻烦。 另一种情况就是你两个项目是用的一套代码,但是最…

一文全解聚碳酸酯PC材料在汽车灯罩制造中的诸多显著优势!汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

聚碳酸酯PC材料在汽车灯罩制造中具有诸多显著优势。除了优异的抗冲击性、透明性、耐热性和稳定性外&#xff0c;还有以下一些重要优势&#xff1a; 出色的光学性能&#xff1a;PC材料的光学性能优异&#xff0c;能够确保灯罩内的光源均匀分布&#xff0c;减少光斑和眩光&#…

新人学习笔记值(初始JavaScript)

一、Java Script是什么 1.Java Script是世界上最流行的语言之一&#xff0c;是一种运行在客户端的脚本语言&#xff08;script是脚本的意思&#xff09; 2.脚本语言&#xff1a;不需要编译&#xff0c;运行过程中由js解释器&#xff08;js引擎&#xff09;进行解释并运行 3.现在…

3dmax材质库导入方法?3dmax云渲染速度体验

3ds Max 材质库包含多种素材&#xff0c;如金属、木材、布料和石材等&#xff0c;但用户在导入材质时常遇到问题。本文将介绍如何在3ds Max中成功导入材质&#xff0c;并探讨使用云渲染服务来加速渲染过程&#xff0c;提高项目效率。 一、3dmax材质库导入教程 自建材质导入方法…

胖东来5月生鲜陈列欣赏

【免责声明】&#xff1a;凡未注明来源的图文内容&#xff0c;版权归原作者所有。本平台所发稿件、图片均用于学习交流&#xff0c;不代表赞同文章观点和对其真实性负责&#xff0c;不用作商业用途。若文章涉及版权&#xff0c;请将马上联系&#xff0c;安排删除。

Google Chrome 设备工具栏原理

1.不同预览模式 2.计算出缩放比 3.固定滚动偏移 关键代码&#xff1a; overview&#xff1a; ratioW getChildRect().width / getParentRect().width ratioH getChildRect().height / getParentRect().height maxRatio max(ratioW, ratioH) if(maxRatio < 1) return 1 …

商业银行总分支数据分发的核心问题是什么?如何解决?

银行业对一个国家至关重要&#xff0c;关乎国计民生。银行为我国经济建设分配资金&#xff0c;是社会再生产顺 利进行的纽带&#xff0c;它能掌握和反应社会经济活动的信息&#xff0c;为企业和政府作出正确的经济决策提供 必要的依据。通过银行&#xff0c;可以对国民经济各部…

白话机器学习4:小波分解的原理与Python代码实现

小波去噪可以想象成使用一把“筛子”来过滤信号。这个“筛子”能够根据信号的不同频率成分&#xff0c;将其分解成多个层次。在这个过程中&#xff0c;信号的重要信息通常包含在低频部分&#xff0c;而噪声则多分布在高频部分。 将信号通过这个“筛子”分解后&#xff0c;我们可…

OpenAI 重磅发布GPT 4o!可以视频聊天的AI?

OpenAI 重磅发布GPT 4o&#xff01; 前言 就在今日&#xff0c;OpenAI发布了ChatGPT-4o版本&#xff0c;技术主管 Mira Murati 在直播中表示GPT-4o对比之前版本速度更快&#xff0c;在文本、视频和音频方面的能力也都有所提高。值得注意的是它还可以让用户与 ChatGPT 进行视频聊…

Vue3使用datav3报错的三个问题解决

我这里写的是按需引入 报错问题Cannot find module dataview/datav-vue3 修改datav源码中的package.json文件 修改为 "module": "./es/index.mjs", 然就就会遇见新的报错问题 报错问题TypeError: Cannot read properties of null (reading $el) 然后修改…

QT切换控件布局

1、切换前垂直布局 2、切换后水平布局 3、关键代码 qDebug() << "开始切换布局";QWidget *widget centralWidget();QLayout *layout widget->layout();if(layout){while(layout->count()){QLayoutItem *item layout->takeAt(0);if(item->layout…

后仿真中的关于延时问题(延迟类型选择和脉冲控制)

目录 通过前面的文章提到,从物理特性角度出发,仿真中存在两种延时:惯性延时和传输延时。那么,实际仿真电路过程中,我们究竟选择的哪种模式呢? 一 指定传输延迟类型 传输延迟类型不是默认的延迟类型。我们需要显示指定它。 1.1 module-path delay VCS 仿真中添加如下三…

物联网促进信息化——​青创智通工业物联网解决方案​

随着传感器网络&#xff08;WSN)、无线射频识别&#xff08;RFID&#xff09;以及微电子机械系统(MEIVIS&#xff09;等技术的不断成熟,扩展了人们对信息获取和使用的能力&#xff0c;并将提高制造效率、改善产品质量、降低产品成本和资源消耗、为用户提供更加透明和个性化的服…