手把手教你用React做一个Excel导入功能,看完就能用!

前言

最近项目需要做个Excel导入功能,网上找了一圈发现要么太复杂要么不能用,干脆自己写一个。这篇文章就是记录整个开发过程,代码可以直接复制粘贴到你的项目里用。

先看看效果

这个组件能干啥:

  • 上传Excel文件(.xlsx和.xls都支持)
  • 自动识别表格内容,第一行当表头
  • 支持多个工作表切换
  • 数据预览,还能编辑
  • 一键导入到系统

开始写代码

第一步:安装依赖

复制代码
npm install xlsx antd

第二步:创建组件

ini 复制代码
import { Button, Select, Table, Upload, Modal } from "antd";
import { useState } from "react";
import * as XLSX from "xlsx";

const TableDataImport = () => {
  // 这些状态用来存数据
  const [tableData, setTableData] = useState([]); // 表格数据
  const [columns, setColumns] = useState([]); // 表格列
  const [tableLoading, setTableLoading] = useState(false); // 加载状态
  const [tableFile, setTableFile] = useState(); // 上传的文件
  const [sheetNames, setSheetNames] = useState([]); // 工作表列表
  const [isModalOpen, setIsModalOpen] = useState(false); // 弹窗显示

  // 核心方法:处理文件上传
  const handleUpload = (file, sheetName) => {
    // 清空之前的数据
    setColumns([]);
    setTableData([]);
    setTableLoading(true);

    // 用FileReader读文件
    const reader = new FileReader();
    reader.onload = (e) => {
      // 把文件转成数组
      const data = new Uint8Array(e.target.result);
      
      // 用xlsx库读Excel
      const workbook = XLSX.read(data, { type: "array" });
      
      // 获取工作表(如果指定了就用指定的,否则用第一个)
      const worksheet = sheetName
        ? workbook.Sheets[sheetName]
        : workbook.Sheets[workbook.SheetNames[0]];

      // 转成JSON数据
      const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });

      // 处理数据:第一行当表头,后面的当数据
      if (jsonData.length > 0) {
        const newData = [];
        jsonData.slice(1).forEach((item, itemIndex) => {
          if (item.length === 0) return;
          
          const obj = { key: itemIndex };
          // 把表头和数据对应起来
          jsonData[0].forEach((header, index) => {
            obj[header] = item[index];
          });
          newData.push(obj);
        });

        // 生成表格列配置
        const columns = jsonData[0].map(header => ({
          title: header,
          dataIndex: header,
          key: header,
          align: "center",
        }));

        setColumns(columns);
        setTableData(newData);
      }

      setTableLoading(false);
    };
    reader.readAsArrayBuffer(file);
  };

  // 切换工作表
  const handleChange = (value) => {
    if (tableFile) handleUpload(tableFile, value);
  };

  // 确定导入
  const handleOk = () => {
    // 这里调用你的导入接口
    console.log('要导入的数据:', tableData);
    setIsModalOpen(false);
    // 清空数据
    setTableData([]);
    setColumns([]);
  };

  return (
    <div>
      {/* 弹窗 */}
      <Modal
        title="Excel导入"
        open={isModalOpen}
        onOk={handleOk}
        onCancel={() => setIsModalOpen(false)}
        width={800}
        okText="导入"
        cancelText="取消"
      >
        <div style={{ margin: "20px 0" }}>
          {/* 文件上传 */}
          <Upload
            beforeUpload={(file) => {
              // 检查文件类型
              const isExcel = /.(xlsx|xls)$/.test(file.name.toLowerCase());
              if (!isExcel) {
                alert("请上传Excel文件(.xlsx 或 .xls)");
                return false;
              }
              
              setTableFile(file);
              handleUpload(file);
              return false; // 阻止自动上传
            }}
          >
            <Button>上传Excel文件</Button>
          </Upload>

          {/* 工作表选择 */}
          {sheetNames.length > 0 && (
            <div style={{ marginTop: 20 }}>
              <span>选择工作表:</span>
              <Select
                style={{ width: 200, marginLeft: 10 }}
                onChange={handleChange}
                options={sheetNames.map(name => ({
                  label: name,
                  value: name
                }))}
              />
            </div>
          )}
        </div>

        {/* 数据预览表格 */}
        <Table
          loading={tableLoading}
          dataSource={tableData}
          columns={columns}
          scroll={{ y: 400 }}
          size="small"
        />
      </Modal>

      {/* 触发按钮 */}
      <Button onClick={() => setIsModalOpen(true)} type="primary">
        导入Excel
      </Button>
    </div>
  );
};

export default TableDataImport;

关键点解释

1. 文件读取流程

javascript 复制代码
用户上传文件 → FileReader读取 → xlsx库解析 → 转成JSON → 显示在表格里

2. 数据转换逻辑

Excel的第一行自动变成表格的表头,下面的行变成数据行。比如:

css 复制代码
Excel内容:
姓名    年龄    城市
张三    25     北京
李四    30     上海

转换后:
columns: [{title: '姓名', dataIndex: '姓名'}, {title: '年龄', dataIndex: '年龄'}, {title: '城市', dataIndex: '城市'}]
data: [{姓名: '张三', 年龄: 25, 城市: '北京'}, {姓名: '李四', 年龄: 30, 城市: '上海'}]

3. 工作表切换

如果你的Excel有多个工作表,组件会自动识别并让你选择用哪个。

怎么用

1. 复制代码到你的项目

把上面的代码复制到一个新文件,比如 ExcelImport.tsx

2. 在需要的地方引入

javascript 复制代码
import ExcelImport from './ExcelImport';

// 在你的页面里
<ExcelImport />

3. 修改导入逻辑

在 handleOk 方法里,把 console.log 改成你的实际导入逻辑:

scss 复制代码
const handleOk = () => {
  // 调用你的API
  api.importData(tableData).then(() => {
    message.success('导入成功!');
    setIsModalOpen(false);
  });
};

常见问题

Q: 为什么上传文件后没反应?

A: 检查浏览器控制台有没有报错,通常是文件格式不对或者xlsx库没装好。

Q: 数据格式不对怎么办?

A: 确保Excel第一行是表头,数据从第二行开始。空行会被自动过滤掉。

Q: 想支持更多文件格式?

A: 在 beforeUpload 里加文件类型判断就行。

总结

这个组件其实不难,核心就是:

  1. 用FileReader读文件
  1. 用xlsx库解析Excel
  1. 把数据转成表格能用的格式

本期内容就到这里,各位大佬觉得有用可以收藏+关注,另外主页有火柴能点着的干货哦!!

相关推荐
蓝瑟忧伤13 小时前
前端技术新十年:从工程体系到智能化开发的全景演进
前端
Baklib梅梅13 小时前
员工手册:保障运营一致性与提升组织效率的核心载体
前端·ruby on rails·前端框架·ruby
IT_陈寒14 小时前
Redis性能翻倍的5个冷门技巧,90%开发者都不知道第3个!
前端·人工智能·后端
jingling55515 小时前
vue | 在 Vue 3 项目中集成高德地图(AMap)
前端·javascript·vue.js
油丶酸萝卜别吃15 小时前
Vue3 中如何在 setup 语法糖下,通过 Layer 弹窗组件弹出自定义 Vue 组件?
前端·vue.js·arcgis
J***Q2921 天前
Vue数据可视化
前端·vue.js·信息可视化
ttod_qzstudio1 天前
深入理解 Vue 3 的 h 函数:构建动态 UI 的利器
前端·vue.js
_大龄1 天前
前端解析excel
前端·excel
一叶茶1 天前
移动端平板打开的三种模式。
前端·javascript
前端大卫1 天前
一文搞懂 Webpack 分包:async、initial 与 all 的区别【附源码】
前端