React实现Table组件导入导出excel

1,415 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

前言

在b端产品开发中经常需要使用到表格,为了方便离线查看数据,很多时候需要导出excel或者csv文件进行浏览。 本篇文章实现了xlsx文件的导入导出,以及对接antdesign的Table组件。

搭建界面

包含导入,导出按钮,以及一个antdesign的Table组件

import { useState } from 'react';
import { Table, Button, Upload } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import styled from 'styled-components';
import * as XLSX from "xlsx";

const Wrapper = styled.div`
  width: 600px;
  margin: 0 auto;
`

export default function Demo() {
  const [dataSource, setDataSource] = useState([])
  const [columns, setColumns] = useState([
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: '年龄',
      dataIndex: 'age',
      key: 'age',
    },
    {
      title: '住址',
      dataIndex: 'address',
      key: 'address',
    },
  ]);

  return <Wrapper>
    < div className='btns' >
      <Button onClick={exportXlsx}>导出</Button>
      <Upload {...UploadProps}>
        <Button icon={<UploadOutlined />}>导入</Button>
      </Upload>
    </div >
    <Table dataSource={dataSource} columns={columns} />
  </Wrapper >;
}

效果图

z1.jpg

xlsx api介绍

该package支持多种文件的读取与写入,本篇文章以xlsx与csv文件为主。

导出

  • XLSX.utils.book_new()

    创建一个空的excel对象

  • XLSX.utils.aoa_to_sheet(dataSource, columns)

    根据dataSource与columns创建一个sheet。(sheet就是excel文件中的一页)

  • XLSX.utils.book_append_sheet()

    将创建的一个sheet放到空的excel对象中

  • XLSX.writeFile

    将excel对象写入到系统磁盘中

导入

  • XLSX.read

    读取本地的excel或者csv文件

  • workbook.SheetNames[n]

    获取读取的文件的第n个sheet页

  • XLSX.utils.sheet_to_json

    将读取的文件转换为json格式

实现导入xlsx

确定导入文件的类型

const UploadProps = {
    accept: ".xlsx",
    // 文件上传之前的回调
    beforeUpload: importXLsx
}

读取文件

我们使用的antdesign的Upload组件,需要在上述的importXlsx中编写逻辑。

为了防止文件读取完毕后,onload回调还没注册,所以将onload写在readAsBinaryString之前。

const importXLsx = (file) => {
    // 创建一个file读取器
    const fileReader = new FileReader();
    // 文件读取完毕后的回调,
    fileReader.onload = ((e) => {
      const workbook = XLSX.read(e.target.result, {
        type: "binary",
      });
      const wsname = workbook.SheetNames[0];
      const sheetJson = XLSX.utils.sheet_to_json(workbook.Sheets[wsname]);
      // 将数据转换为Table组件所需格式
      const ds = dataToDatasource(sheetJson);
      setDataSource(ds)
    })
    // 以二进制字符串的形式读取本地文件
    fileReader.readAsBinaryString(file);
    // 阻止Upload组件的上传逻辑
    return false;
  }

文件转换

由于XLSX.utils.sheet_to_json读取文件后的格式与Table组件所需的dataSource格式不一样,需要进行转换

const dataToDatasource = (data) => {
    const list = [];
    data.forEach((row) => {
      const obj = {};
      Object.entries(row).forEach(([key, value]) => {
        obj[key] = value;
      })
      list.push(getDataIndexByTitle(obj, columns))
    })
    return list
  }

z2.jpg

效果图

z3.gif

实现导出xlsx

  • 创建excel文件对象

  • 将dataSource转换为xlsx包所需的格式

  • 创建sheet对象

  • 将sheet添加到xlsx对象中

  • 写入文件

const exportXlsx = () => {
    var workbook = XLSX.utils.book_new();
    // // 将数据转换为xlsx包所需格式
    const data = dataSourceToData(dataSource, columns)
    var worksheet = XLSX.utils.aoa_to_sheet(data);
    XLSX.utils.book_append_sheet(workbook, worksheet, "page1");
    XLSX.writeFile(workbook, "file5.xlsx", { bookType: "xlsx" });
  }

文件转换

由于XLSX.utils.aoa_to_sheet需要的文件格式与dataSource格式不一样,需要进行转换

const dataSourceToData = (ds, cols) => {
    const columns = cols.map(item => item.dataIndex);
    const list = [];
    const tHead = cols.map(item => item.title);
    list.push(tHead);
    ds.forEach(d => {
      const row = []
      columns.forEach(c => {
        row.push(d[c])
      })
      list.push(row)
    })
    return list
  }

z5.jpg

效果图

z4.gif 点赞收藏不迷路