前端实现导出excel表格(合并表头)

news2024/10/6 12:35:00
需求:勾选行导出为excel表格(合并表头 )

在这里插入图片描述

一、安装插件
npm install --save file-saver xlsx

运行项目报如下警告的话 运行npm install xlsx@0.16.0 --save 来降低版本号(最初我安装的版本号是0.18.16的版本)再次运行项目就不会报如下警告了

在这里插入图片描述

二、新建一个excel.js文件

我存放的路径如下图(下面代码会引入此路径):

在这里插入图片描述
excel.js代码如下:

import { saveAs } from 'file-saver'
import XLSX from 'xlsx'

function generateArray(table) {
  const out = []
  const rows = table.querySelectorAll('tr')
  const ranges = []
  for (let R = 0; R < rows.length; ++R) {
    const outRow = []
    const row = rows[R]
    const columns = row.querySelectorAll('td')
    for (let C = 0; C < columns.length; ++C) {
      const cell = columns[C]
      let colspan = cell.getAttribute('colspan')
      let rowspan = cell.getAttribute('rowspan')
      let cellValue = cell.innerText
      if (cellValue !== '' && cellValue === +cellValue) cellValue = +cellValue

      ranges.forEach(function (range) {
        if (
          R >= range.s.r &&
          R <= range.e.r &&
          outRow.length >= range.s.c &&
          outRow.length <= range.e.c
        ) {
          for (let i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null)
        }
      })

      if (rowspan || colspan) {
        rowspan = rowspan || 1
        colspan = colspan || 1
        ranges.push({
          s: {
            r: R,
            c: outRow.length,
          },
          e: {
            r: R + rowspan - 1,
            c: outRow.length + colspan - 1,
          },
        })
      }

      outRow.push(cellValue !== '' ? cellValue : null)

      if (colspan) for (let k = 0; k < colspan - 1; ++k) outRow.push(null)
    }
    out.push(outRow)
  }
  return [out, ranges]
}

function datenum(v, date1904) {
  if (date1904) v += 1462
  const epoch = Date.parse(v)
  return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
}

function sheet_from_array_of_arrays(data) {
  const ws = {}
  const range = {
    s: {
      c: 10000000,
      r: 10000000,
    },
    e: {
      c: 0,
      r: 0,
    },
  }
  for (let R = 0; R !== data.length; ++R) {
    for (let C = 0; C !== data[R].length; ++C) {
      if (range.s.r > R) range.s.r = R
      if (range.s.c > C) range.s.c = C
      if (range.e.r < R) range.e.r = R
      if (range.e.c < C) range.e.c = C
      const cell = {
        v: data[R][C],
      }
      if (cell.v === null) continue
      const cell_ref = XLSX.utils.encode_cell({
        c: C,
        r: R,
      })

      if (typeof cell.v === 'number') cell.t = 'n'
      else if (typeof cell.v === 'boolean') cell.t = 'b'
      else if (cell.v instanceof Date) {
        cell.t = 'n'
        cell.z = XLSX.SSF._table[14]
        cell.v = datenum(cell.v)
      } else cell.t = 's'

      ws[cell_ref] = cell
    }
  }
  if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range)
  return ws
}

function Workbook() {
  if (!(this instanceof Workbook)) return new Workbook()
  this.SheetNames = []
  this.Sheets = {}
}

function s2ab(s) {
  const buf = new ArrayBuffer(s.length)
  const view = new Uint8Array(buf)
  for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
  return buf
}

export function export_table_to_excel(id) {
  const theTable = document.getElementById(id)
  const oo = generateArray(theTable)
  const ranges = oo[1]

  const data = oo[0]
  const ws_name = 'SheetJS'

  const wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data)

  ws['!merges'] = ranges

  wb.SheetNames.push(ws_name)
  wb.Sheets[ws_name] = ws

  const wbout = XLSX.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary',
  })

  saveAs(
    new Blob([s2ab(wbout)], {
      type: 'application/octet-stream',
    }),
    'test.xlsx'
  )
}

export function export_json_to_excel({
  multiHeader = [],
  header,
  data,
  filename,
  merges = [],
  autoWidth = true,
  bookType = 'xlsx',
} = {}) {
  filename = filename || 'excel-list'
  data = [...data]
  data.unshift(header)

  for (let i = multiHeader.length - 1; i > -1; i--) {
    data.unshift(multiHeader[i])
  }

  const ws_name = 'SheetJS'
  const wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data)

  if (merges.length > 0) {
    if (!ws['!merges']) ws['!merges'] = []
    merges.forEach((item) => {
      ws['!merges'].push(XLSX.utils.decode_range(item))
    })
  }

  if (autoWidth) {
    const colWidth = data.map((row) =>
      row.map((val) => {
        if (val === null) {
          return {
            wch: 10,
          }
        } else if (val.toString().charCodeAt(0) > 255) {
          return {
            wch: val.toString().length * 2,
          }
        } else {
          return {
            wch: val.toString().length,
          }
        }
      })
    )
    const result = colWidth[0]
    for (let i = 1; i < colWidth.length; i++) {
      for (let j = 0; j < colWidth[i].length; j++) {
        if (result[j]['wch'] < colWidth[i][j]['wch']) {
          result[j]['wch'] = colWidth[i][j]['wch']
        }
      }
    }
    ws['!cols'] = result
  }

  wb.SheetNames.push(ws_name)
  wb.Sheets[ws_name] = ws

  const wbout = XLSX.write(wb, {
    bookType: bookType,
    bookSST: false,
    type: 'binary',
  })
  saveAs(
    new Blob([s2ab(wbout)], {
      type: 'application/octet-stream',
    }),
    `${filename}.${bookType}`
  )
}

上面代码中修改默认导出表格的名称

在这里插入图片描述

三、组件中引入使用

<template>
  <div class="select-excel-container">
    <el-form :inline="true">
      <el-form-item>
        <el-input v-model="filename"  placeholder="请输出导出文件名称" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleDownload">
          导出选中行
        </el-button>
      </el-form-item>
    </el-form>

    <el-table
      ref="multipleTable"
      border
      :data="list"
      @selection-change="handleSelectionChange"
    >
      <el-table-column align="center" type="selection" />
      <el-table-column align="center" label="序号" width="55">
        <template #default="{ $index }">
          {{ $index + 1 }}
        </template>
      </el-table-column>
      <el-table-column align="center" label="标题">
        <template #default="{ row }">
          {{ row.title }}
        </template>
      </el-table-column>
      <el-table-column align="center" label="作者">
        <template #default="{ row }">
          <el-tag>{{ row.author }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column align="center" label="访问量" width="115">
        <template #default="{ row }">
          {{ row.pageViews }}
        </template>
      </el-table-column>
      <el-table-column align="center" label="时间">
        <template #default="{ row }">
          <span>{{ row.datetime }}</span>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: "ExportSelectExcel",
  data() {
    return {
      list: [
        {
          uuid: "3AAD8907-5Efb-9D3F-0219-8f80e67a5634",
          id: "230000198507241209",
          title: "Htqr",
          description: "较无己文日需说事酸热由写来将两市细队。",
          status: "published",
          author: "贺娟",
          datetime: "2010-09-29 07:43:20",
          pageViews: 4179,
          img:
            "https://cdn.jsdelivr.net/gh/chuzhixin/image/table/vab-image-10.jpg",
          switch: true,
          percent: 90,
          rate: 2,
          percentage: 3,
        },
        {
          uuid: "75E17e52-f7f5-CbB0-8DD5-Ef988cbe244D",
          id: "820000202202052027",
          title: "Nfxemhvce",
          description: "集最度达边光设儿就管具七土维对多身。",
          status: "draft",
          author: "郝敏",
          datetime: "1975-03-22 03:21:01",
          pageViews: 3648,
          img:
            "https://cdn.jsdelivr.net/gh/chuzhixin/image/table/vab-image-25.jpg",
          switch: true,
          percent: 85,
          rate: 3,
          percentage: 36,
        },
        {
          uuid: "d2f5cAE8-E1df-9997-918B-4C24cbCDbe82",
          id: "460000199510077216",
          title: "Dcpdyqjxpo",
          description: "都际一这他派效政认治计百这。",
          status: "published",
          author: "乔超",
          datetime: "2011-01-07 17:03:16",
          pageViews: 3799,
          img:
            "https://cdn.jsdelivr.net/gh/chuzhixin/image/table/vab-image-3.jpg",
          switch: true,
          percent: 90,
          rate: 2,
          percentage: 87,
        },
        {
          uuid: "daA2f356-1CAA-9FEA-DaE3-5ED6eFBd794C",
          id: "630000200001199589",
          title: "Hrhhzwj Drtf",
          description: "第使道具所活交克小术表商认么。",
          status: "draft",
          author: "方磊",
          datetime: "1990-03-07 20:29:11",
          pageViews: 3816,
          img:
            "https://cdn.jsdelivr.net/gh/chuzhixin/image/table/vab-image-22.jpg",
          switch: true,
          percent: 90,
          rate: 4,
          percentage: 65,
        },
        {
          uuid: "e989d59B-b2CE-33E9-2dFd-0B6e93EbadEB",
          id: "520000201106102834",
          title: "Kinltlj",
          description: "方西严办政受定每组龙适老看同将。",
          status: "draft",
          author: "罗勇",
          datetime: "1998-06-03 06:10:48",
          pageViews: 322,
          img:
            "https://cdn.jsdelivr.net/gh/chuzhixin/image/table/vab-image-9.jpg",
          switch: false,
          percent: 82,
          rate: 3,
          percentage: 70,
        },
        {
          uuid: "1DE3AEED-AFCC-bbf9-b5E8-C99e303Decdf",
          id: "340000199509093035",
          title: "Nhsfyt Ivuof",
          description: "干导划此世由空单接马发型府头。",
          status: "deleted",
          author: "熊芳",
          datetime: "1997-02-20 01:07:34",
          pageViews: 1068,
          img:
            "https://cdn.jsdelivr.net/gh/chuzhixin/image/table/vab-image-28.jpg",
          switch: false,
          percent: 80,
          rate: 3,
          percentage: 35,
        },
        {
          uuid: "fcE302cF-D71b-dAB6-c2D5-565efE1E8335",
          id: "54000020161030747X",
          title: "Wjomrsvy Gltuchp",
          description: "外改也色入王表件回里把为且得。",
          status: "published",
          author: "卢秀英",
          datetime: "2018-12-16 05:19:06",
          pageViews: 2580,
          img:
            "https://cdn.jsdelivr.net/gh/chuzhixin/image/table/vab-image-10.jpg",
          switch: true,
          percent: 90,
          rate: 3,
          percentage: 90,
        },
        {
          uuid: "8A868c6f-bAf6-A935-FbFC-DEAF2ad3EC3a",
          id: "310000201202123580",
          title: "Frmdpvb",
          description: "般时将写中千该式备重见叫技。",
          status: "deleted",
          author: "孔涛",
          datetime: "2012-10-10 04:59:24",
          pageViews: 1969,
          img:
            "https://cdn.jsdelivr.net/gh/chuzhixin/image/table/vab-image-1.jpg",
          switch: true,
          percent: 87,
          rate: 4,
          percentage: 61,
        },

      ],
      multipleSelection: [],
      downloadLoading: false,
      filename: "",
    };
  },
  created() {
  },
  methods: {
    handleSelectionChange(val) {
      this.multipleSelection = val;
    },
    handleDownload() {
      if (this.multipleSelection.length) {
        this.downloadLoading = true;
        import("@/utils/excel").then((excel) => {
          const multiHeader = [["Id", "Title", "", "", "Date","Description"]];
          const tHeader = ["", "Title", "Author", "Readings", "","Description"];
          const filterVal = ["id", "title", "author", "pageViews", "datetime","description"];
          const list = this.multipleSelection;
          const data = this.formatJson(filterVal, list);
          const merges = ['A1:A2','B1:D1','E1:E2']
          console.log(data);
          console.log(list);

          excel.export_json_to_excel({
            multiHeader,
            header: tHeader,
            data,
            filename: this.filename,
            merges
          });
          this.$refs.multipleTable.clearSelection();
          this.downloadLoading = false;
        });
      } else {
        this.$message("请至少选择一行");
      }
    },
    formatJson(filterVal, jsonData) {
      return jsonData.map((v) => filterVal.map((j) => v[j]));
    },
  },
};
</script>

<style lang="less">
.select-excel-container {
  margin-top: 50px;
}
</style>


导出表格结果如下:

在这里插入图片描述

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

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

相关文章

VS构建项目报错信息及解决办法01

报错信息及解决1&#xff1a; 报错信息详情&#xff1a;1>MSVCRT.lib(exe_winmain.obj) : error LNK2019: 无法解析的外部符号 _WinMain16&#xff0c;该符号在函数 "int cdecl scrt_common_main_seh(void)" (?__scrt_common_main_sehYAHXZ) 中被引用 原因&…

SAP RFC介绍(sRFC/aRFC/tRFC/qRFC/pRFC)

异步RFC&#xff1a; aRFC后缀&#xff1a; STARTING NEW TASK CALL FUNCTION - STARTING NEW TASK / RECEIVE / WAIT UNTIL tRFC 后缀&#xff1a; IN BACKGROUND TASK. CALL FUNCTION - IN BACKGROUND TASK qRFC 是tRFC的一个扩展。它允许你将多个tRFC调用序列化为一个…

RocketMQ集群4.9.2升级4.9.6版本

本文主要记录生产环境短暂停机升级RocketMQ版本的过程 一、整体思路 1.将生产环境MQ4.9.2集群同步到测试环境&#xff0c;并启动&#xff0c;确保正常运行。 2.参照4.9.2配置4.9.6集群 3.停掉4.9.2集群&#xff0c;启动4.9.6集群&#xff0c;测试确保正常运行。 4.停掉4.9.6集…

Python Web开发技巧VII

目录 装饰器inject_serializer 装饰器atomic rebase git 清理add的数据 查看git的当前工作目录 makemigrations文件名称 action(detailTrue, methods["GET"]) 如何只取序列化器的一个字段进行返回 Response和JsonResponse有什么区别 序列化器填表和单字段如…

理解Android中不同的Context

作者&#xff1a;两日的blog Context是什么&#xff0c;有什么用 在Android开发中&#xff0c;Context是一个抽象类&#xff0c;它是Android应用程序环境的一部分。它提供了访问应用程序资源和执行各种操作的接口。可以说&#xff0c;Context是Android应用程序与系统环境进行交…

LoadRunner使用教程

1. LoadRunner简介 LoadRunner是一款广泛使用的性能测试工具 可以对各种应用程序进行性能测试&#xff0c;包括Web应用程序、移动应用程序、企业级应用程序等。它提供了一个综合的性能测试解决方案&#xff0c;包括测试计划设计、脚本录制、测试执行、结果分析和报告生成等功…

三、函数-5.流程函数

一、常见函数 【对比】 二、示例 1、if 和 ifnull -- if(value, t, f) 如果value为true&#xff0c;则返回t&#xff0c;否则返回f ok select if(true, ok, error);-- ifnull(value1, value2) 如果value1不为空&#xff0c;返回value1&#xff0c;否则返回value2&#…

MFC表格控件CListCtrl的改造及用法

1、目的 简单描述MFC的表格控件使用方法。Qt适用习惯了以后MFC用的比较别扭&#xff0c;因此记录一下以备后续复制代码使用。由于MFC原生的CListCtrl比较局限&#xff0c;比如无法改变表格的背景色、文字颜色等设定&#xff0c;因此先对CListCtrl类进行重写&#xff0c;以便满足…

哪些报表工具更适合中国企业?看完本文就知道了

企业级报表工具是指能够处理大量数据、支持多种数据源连接、具有强大的数据分析和可视化功能的工具。进入大数据时代&#xff0c;企业数据量剧增、分析需求精细化且要求高效率、高灵活自主性&#xff0c;一般都采用BI报表工具来做智能化、可视化数据分析&#xff0c;推动企业的…

Neo4j数据库中导入CSV示例数据

本文简要介绍Neo4j数据库以及如何从CSV文件中导入示例数据&#xff0c;方便我们快速学习测试图数据库。首先介绍简单数据模型以及基本图查询概念&#xff0c;然后通过LOAD CSV命令导入数据&#xff0c;生成节点和关系。 环境准备 读者可以快速安装Neo4j Desktop&#xff0c;启…

Mysql中(@i:=@i+1)的介绍

i:i1 表达式 生成伪列实现自增序列 语法&#xff1a; select (i:i1) as ,t.* from table_name t,(select i:0) as j (i:i1)代表定义一个变量&#xff0c;每次叠加 1&#xff1b; (select i:0) as j 代表建立一个临时表&#xff0c;j是随便取的表名&#xff0c;但别名一定…

python和c++哪个更值得学,python和c++学哪个简单

大家好&#xff0c;本文将围绕python和c哪个更值得学展开说明&#xff0c;python和c学哪个简单是一个很多人都想弄明白的事情&#xff0c;想搞清楚c和python哪个好学需要先了解以下几个事情。 1、想学编程&#xff0c;选择Python 还是Java或者C&#xff1f; 首先&#xff0c;我…

MySQL索引失效原因及解决方案

MySQL索引失效原因及解决方案 在使用MySQL数据库时&#xff0c;索引是一种重要的性能优化工具。然而&#xff0c;有时候我们可能会遇到索引失效的情况。本文将介绍几种常见的MySQL索引失效原因以及相应的解决方案&#xff0c;并提供SQL语句的错误示例和正确示例。 1. 字符串字…

HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 二)

Prop装饰器&#xff1a;父子单向同步 Prop装饰的变量可以和父组件建立单向的同步关系。Prop装饰的变量是可变的&#xff0c;但是变化不会同步回其父组件。 概述 Prop装饰的变量和父组件建立单向的同步关系&#xff1a; Prop变量允许在本地修改&#xff0c;但修改后的变化不会…

tinkerCAD案例:11.制作齿轮

tinkerCAD案例&#xff1a;11.制作齿轮 制作齿轮 Add a cylinder to be the main part of the gear. 添加一个圆柱体作为齿轮的主要部分。 说明 Click and drag a cylinder onto the Workplane. 单击圆柱体并将其拖动到工作平面上。 Change the cylinder dimensions to 35mm …

四、约束-1.概述

一、概念 约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。 二、目的 保证数据库中数据的正确、有效性和完整性。 三、分类

视觉套件专项活动!与飞桨技术专家一起提升技术实力,更多荣誉奖励等你领取

作为中国最早开源的深度学习框架&#xff0c;飞桨深度践行开源理念&#xff0c;开放拥抱社区&#xff0c;重视生态构建&#xff0c;与开发者和生态伙伴共成长&#xff0c;已成为国内综合竞争力第一的产业级深度学习平台。截至目前&#xff0c;飞桨已凝聚750万名开发者。 在飞桨…

i.MX6ULL(十九) linux gpio子系统

一 简介 pinctrl 子系统重点是设置 PIN( 有的 SOC 叫做 PAD) 的复用 和电气属性&#xff0c; 如果 pinctrl 子系统将一个 PIN 复用为 GPIO 的话&#xff0c;那么接下来就要用到 gpio 子系 统了。gpio 子系统顾名思义&#xff0c;就是用于初始化 GPIO 并且提供相…

idea,选中同一个变量高亮显示

阅读复杂代码时&#xff0c;我们经常因为找不清变量位置&#xff0c;而浪费精力重新去看变量名。 效果展示&#xff1a; 在设置里直接搜索按照步骤&#xff0c;勾选然后修改选中变量时的变量背景颜色和字体颜色 这里是设置选中变量时&#xff0c;其他变量的背景颜色和字体颜色…

终于搞懂!数字化、信息化、智能化,到底有什么不同?

引言 随着科技的飞速发展&#xff0c;数字化、信息化和智能化这三个术语在各行各业中频繁出现。然而&#xff0c;许多人对它们之间的区别并不十分清楚。本文旨在阐明数字化、信息化和智能化的含义&#xff0c;探讨它们在实践中的应用&#xff0c;并梳理其异同之处。 一、数字化…