[特殊字符] 使用 Handsontable 构建一个支持 Excel 公式计算的动态表格
在 Web 应用中,处理表格数据并提供 Excel 级的功能(如公式计算、数据导入导出)一直是个挑战。今天,我将带你使用 React + Handsontable 搭建一个强大的 Excel 风格表格,支持 公式计算、Excel 文件导入导出,并实现 动态单元格样式。
🎯 项目目标
-
✅ 创建一个可编辑的 Excel 风格表格
-
✅ 支持 Excel 公式解析(如
=B1+10) -
✅ 支持 Excel 文件导入/导出(.xlsx/.xls)
-
✅ 实现 单元格动态渲染(如公式高亮)
📦 依赖安装
首先,确保你的 React 项目已创建(若没有,可用 npx create-react-app my-app 创建)。然后,安装必要的依赖项:
npm install @handsontable/react handsontable mathjs xlsx react-i18next
📌 核心代码解析
1️⃣ 创建 Excel 风格的 Handsontable 表格
import React, { useState } from 'react';
import { HotTable } from '@handsontable/react';
import { useTranslation } from 'react-i18next';
import * as math from 'mathjs';
import * as XLSX from 'xlsx';
import 'handsontable/dist/handsontable.full.min.css';const ExcelTable = () => {const { t } = useTranslation();const [data, setData] = useState([[t('name'), t('age'), t('city'), 'Total'],['John', 30, 'New York', '=B1+10'],['Alice', 25, 'London', '=B2*2'],]);
-
useState初始化数据,支持 公式输入(如=B1+10) -
Handsontable 是一个轻量级但功能强大的表格库,支持 Excel 风格的操作
2️⃣ 实现公式计算功能
const calculateFormula = (value, row, col, dataArray) => {if (typeof value === 'string' && value.startsWith('=')) {try {const formula = value.slice(1).replace(/[A-Z]\d+/g, (cell) => {const colLetter = cell.match(/[A-Z]/)[0];const rowNum = parseInt(cell.match(/\d+/)[0], 10) - 1;const colNum = colLetter.charCodeAt(0) - 65;return dataArray[rowNum][colNum];});return math.evaluate(formula);} catch (e) {return '#ERROR';}}return value;
};
-
解析 Excel 格式的公式(
=B1+10) -
将公式转换为 数学计算表达式 并使用
math.evaluate()计算结果 -
错误处理:如果解析失败,返回
#ERROR
3️⃣ 实现 Excel 文件导入功能
const handleImport = (event) => {const file = event.target.files[0];const reader = new FileReader();reader.onload = (e) => {const binaryStr = e.target.result;const workbook = XLSX.read(binaryStr, { type: 'binary' });const sheetName = workbook.SheetNames[0];const sheet = workbook.Sheets[sheetName];const importedData = XLSX.utils.sheet_to_json(sheet, { header: 1 });setData(importedData);};reader.readAsBinaryString(file);
};
-
用户选择 Excel 文件
-
解析 Excel 数据 并转换为 JavaScript 数组
-
更新 Handsontable 的
data以渲染新数据
4️⃣ 实现 Excel 文件导出功能
const handleExport = () => {const ws = XLSX.utils.aoa_to_sheet(data);const wb = XLSX.utils.book_new();XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');XLSX.writeFile(wb, 'exported_excel.xlsx');
};
-
将 Handsontable 数据 转换为 Excel sheet
-
创建新的 Excel 工作簿
-
下载 Excel 文件,实现 导出功能
5️⃣ 动态单元格渲染(公式高亮)
<HotTabledata={data}rowHeaders={true}colHeaders={true}contextMenu={true}stretchH="all"beforeChange={(changes) => {changes.forEach(([row, col, , newValue]) => {data[row][col] = newValue;});setData([...data]);}}afterGetCellMeta={(row, col, cellProperties) => {const value = data[row][col];if (typeof value === 'string' && value.startsWith('=')) {cellProperties.readOnly = false;cellProperties.renderer = (instance, td, r, c, prop, val) => {const result = calculateFormula(val, r, c, data);td.innerHTML = result;td.style.backgroundColor = '#e0f7fa'; // 公式单元格高亮};} else {cellProperties.renderer = (instance, td, r, c, prop, val) => {td.innerHTML = val;td.style.backgroundColor = '#ffffff'; // 普通单元格白色背景};}}}cells={(row, col) => {const cellProperties = {};if (row === 0) {cellProperties.className = 'header-cell'; // 表头样式}return cellProperties;}}licenseKey="non-commercial-and-evaluation"
/>
-
检测单元格是否包含公式
-
动态渲染公式计算结果
-
高亮公式单元格 以增强用户体验
完整代码
// src/components/ExcelTable.jsx
import React, { useState } from 'react';
import { HotTable } from '@handsontable/react';
import { useTranslation } from 'react-i18next';
import * as math from 'mathjs';
import * as XLSX from 'xlsx';
import 'handsontable/dist/handsontable.full.min.css';const ExcelTable = () => {const { t } = useTranslation();const [data, setData] = useState([[t('name'), t('age'), t('city'), 'Total'],['John', 30, 'New York', '=B1+10'],['Alice', 25, 'London', '=B2*2'],]);// 计算公式const calculateFormula = (value, row, col, dataArray) => {if (typeof value === 'string' && value.startsWith('=')) {try {const formula = value.slice(1).replace(/[A-Z]\d+/g, (cell) => {const colLetter = cell.match(/[A-Z]/)[0];const rowNum = parseInt(cell.match(/\d+/)[0], 10) - 1;const colNum = colLetter.charCodeAt(0) - 65;return dataArray[rowNum][colNum];});return math.evaluate(formula);} catch (e) {return '#ERROR';}}return value;};// 导入 Excel 文件const handleImport = (event) => {const file = event.target.files[0];const reader = new FileReader();reader.onload = (e) => {const binaryStr = e.target.result;const workbook = XLSX.read(binaryStr, { type: 'binary' });const sheetName = workbook.SheetNames[0];const sheet = workbook.Sheets[sheetName];const importedData = XLSX.utils.sheet_to_json(sheet, { header: 1 });setData(importedData);};reader.readAsBinaryString(file);};// 导出 Excel 文件const handleExport = () => {const ws = XLSX.utils.aoa_to_sheet(data);const wb = XLSX.utils.book_new();XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');XLSX.writeFile(wb, 'exported_excel.xlsx');};return (<div><div style={{ marginBottom: '10px' }}><input type="file" accept=".xlsx, .xls" onChange={handleImport} /><button onClick={handleExport}>Export to Excel</button></div><HotTabledata={data}rowHeaders={true}colHeaders={true}contextMenu={true}stretchH="all"beforeChange={(changes) => {changes.forEach(([row, col, , newValue]) => {data[row][col] = newValue;});setData([...data]);}}afterGetCellMeta={(row, col, cellProperties) => {const value = data[row][col];if (typeof value === 'string' && value.startsWith('=')) {cellProperties.readOnly = false;cellProperties.renderer = (instance, td, r, c, prop, val) => {const result = calculateFormula(val, r, c, data);td.innerHTML = result;td.style.backgroundColor = '#e0f7fa'; // 公式单元格高亮};} else {cellProperties.renderer = (instance, td, r, c, prop, val) => {td.innerHTML = val;td.style.backgroundColor = '#ffffff'; // 普通单元格白色背景};}}}cells={(row, col) => {const cellProperties = {};if (row === 0) {cellProperties.className = 'header-cell'; // 表头样式}return cellProperties;}}licenseKey="non-commercial-and-evaluation"/><style jsx>{.header-cell {background-color: #f0f0f0;font-weight: bold;}}</style></div>);
};export default ExcelTable;
🎉 运行效果
🚀 你现在拥有了一个 功能强大的 Excel 风格表格,支持:
✅ 公式计算(自动计算 =B1+10)
✅ Excel 文件导入/导出
✅ 动态高亮公式单元格
✅ 行列可编辑 & 右键菜单操作
💡 总结
通过 Handsontable + mathjs + xlsx,我们轻松构建了一个 Excel 风格的动态表格。这一方案适用于 财务管理、数据分析、在线表单应用 等场景,提升了数据处理的灵活性!
🔹 完整代码已上传 GitHub(可在评论区留言获取)
🔹 你对这个 Excel 组件有什么优化建议?欢迎评论交流!
🔥 如果觉得有帮助,别忘了点赞 + 收藏! 🎯
相关文章:
[特殊字符] 使用 Handsontable 构建一个支持 Excel 公式计算的动态表格
在 Web 应用中,处理表格数据并提供 Excel 级的功能(如公式计算、数据导入导出)一直是个挑战。今天,我将带你使用 React Handsontable 搭建一个强大的 Excel 风格表格,支持 公式计算、Excel 文件导入导出,并…...
uniapp微信小程序引入vant组件库
1、首先要有uniapp项目,根据vant官方文档使用yarn或npm安装依赖: 1、 yarn init 或 npm init2、 # 通过 npm 安装npm i vant/weapp -S --production# 通过 yarn 安装yarn add vant/weapp --production# 安装 0.x 版本npm i vant-weapp -S --production …...
贪心进阶学习笔记
反悔贪心 贪心是指直接选择局部最优解,不需要考虑之后的影响。 而反悔贪心是在贪心上面加了一个“反悔”的操作,于是又可以撤销之前的“鲁莽行动”,让整个的选择稍微变得“理智一些”。 于是,我个人理解,反悔贪心是…...
Java 大视界 -- Java 大数据在航天遥测数据分析中的技术突破与应用(177)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
架构师面试(二十七):单链表
问题 今天的问题对于架构师来说会相对容易许多。今天出一个【数据结构与算法】相关的题目,醒醒脑。 给一张【单链表】,该单链表有100个节点元素(当然,事先我们是不知道100这个数目的),要获取倒数第8个元素…...
从扩展黎曼泽塔函数构造物质和时空的结构-15
回来考虑泽塔函数, 我们知道, 也就是在平面直角坐标系上反正切函数在x上的变化率,那么不难看出, 就是在s维空间上的“广义”反正切函数在单位p上的变化率,而泽塔函数,就是这些变化率的全乘积, 因…...
数据库访问工具 dbVisitor v6.0.0 发布
dbVisitor 是一款轻量小巧、功能完备的 Java 数据库 ORM 工具,它的前身是 HasorDB,历经 8 年迭代后正式更名为 dbVisitor 并开始独立发展4。以下是关于 dbVisitor v6.0.0 发布的相关信息: 发布说明 在 Maven Central 上可查询到 dbVisitor …...
01背包问题详解 具体样例模拟版
01背包 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 v i v_i vi,价值是 w i w_i wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 …...
网络初识 - Java
网络发展史: 单机时代(独立模式) -> 局域网时代 -> 广域网时代 -> 移动互联网时代 网络互联:将多台计算机链接再一起,完成数据共享。 数据共享的本质是网络数据传输,即计算机之间通过网络来传输数…...
zk基础—5.Curator的使用与剖析一
大纲 1.基于Curator进行基本的zk数据操作 2.基于Curator实现集群元数据管理 3.基于Curator实现HA主备自动切换 4.基于Curator实现Leader选举 5.基于Curator实现分布式Barrier 6.基于Curator实现分布式计数器 7.基于Curator实现zk的节点和子节点监听机制 8.基于Curator创…...
大模型快速 ASGI 服务器uvicorn
基础概念类 1. 什么是 Uvicorn,它的作用是什么? 答案:Uvicorn 是一个基于 Python 的快速 ASGI(异步服务器网关接口)服务器。它的主要作用是作为 Web 应用程序的服务器,负责接收客户端的请求,并…...
每日一题(小白)回溯篇4
深度优先搜索题:找到最长的路径,计算这样的路径有多少条(使用回溯) 分析题意可以得知,每次向前后左右走一步,直至走完16步就算一条走通路径。要求条件是不能超出4*4的范围,不能重复之前的路径。…...
消息队列基础概念及选型,常见解决方案包括消息可靠性、消息有序、消息堆积、重复消费、事务消息
前言 是时候总结下消息队列相关知识点啦!我搓搓搓搓 本文包括消息队列基础概念介绍,常见解决方案包括消息可靠性、消息有序、消息堆积、重复消费、事务消息 参考资料: Kafka常见问题总结 | JavaGuide RocketMQ常见问题总结 | JavaGuide …...
基于STM32与应变片的协作机械臂力反馈控制系统设计与实现---3.3 机械结构改装
3.3 机械臂结构改装设计与实施 一、改装需求分析 1.1 改装类型分级 改装级别涉及范围典型改动周期成本I级(小型)末端执行器工具快换装置1-3天$500-2000II级(中型)关节模块电机/减速器升级1-2周$2000-8000III级(大型)本体结构材质/拓扑优化1-3月$8000+1.2 关键参数变更评…...
k8s进阶之路:本地集群环境搭建
概述 文章将带领大家搭建一个 master 节点,两个 node 节点的 k8s 集群,容器基于 docker,k8s 版本 v1.32。 一、系统安装 安装之前请大家使用虚拟机将 ubuntu24.04 系统安装完毕,我是基于 mac m1 的系统进行安装的,所…...
云服务器实战:用 Nginx 搭建高性能 API 网关与反向代理服务(附完整配置流程)
在如今的 Web 系统架构中,“接口统一出口”已成为必备设计模式——无论是前后端分离、微服务架构,还是多端接入(Web、小程序、App),一个稳定、高性能、可扩展的 API 网关至关重要。 而 Nginx,作为轻量级高…...
C++ STL 详解 ——list 的深度解析与实践指南
在 C 的标准模板库(STL)中,list作为一种重要的序列式容器,以其独特的双向链表结构和丰富的操作功能,在许多编程场景下发挥着关键作用。深入理解list的特性与使用方法,能帮助开发者编写出更高效、灵活的代码…...
按键切换LCD显示后,显示总在第二阶段,而不在第一阶段的问题
这是一个密码锁的程序,当在输入密码后,原本是要重置密码,但是程序总是在输入密码正确后总是跳转置设置第二个密码,而第一个密码总是跳过。 不断修改后, 解决方法 将if语句换成switch语句,这样就可以分离程序…...
护网蓝初面试题
《网安面试指南》https://mp.weixin.qq.com/s/RIVYDmxI9g_TgGrpbdDKtA?token1860256701&langzh_CN 5000篇网安资料库https://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247486065&idx2&snb30ade8200e842743339d428f414475e&chksmc0e4732df793fa3bf39…...
C++11: 智能指针
C11: 智能指针 (一)智能指针原理1.RAll2.智能指针 (二)C11 智能指针1. auto_ptr2. unique_ptr3. shared_ptr4. weak_ptr (三)shared_ptr中存在的问题std::shared_ptr的循环引用 (四)删除器(五&a…...
去中心化预测市场
去中心化预测市场 核心概念 预测市场类型: 类别型市场:二元结果(YES/NO),例如“BTC在2024年突破10万美元?” 多选型市场:多个选项(如总统候选人),赔付基于…...
从零实现本地大模型RAG部署
1. RAG概念 RAG(Retrieval-Augmented Generation)即检索增强生成,是一种结合信息检索与大型语言模型(大模型)的技术。从外部知识库(如文档、数据库或网页)中实时检索相关信息,并将其…...
使用 Python 连接 PostgreSQL 数据库,从 `mimic - III` 数据库中筛选数据并导出特定的数据图表
要使用 Python 连接 PostgreSQL 数据库,从 mimic - III 数据库中筛选数据并导出特定的数据图表,你可以按照以下步骤操作: 安装所需的库:psycopg2 用于连接 PostgreSQL 数据库,pandas 用于数据处理,matplot…...
【Linux系统篇】:探索文件系统原理--硬件磁盘、文件系统与链接的“三体宇宙”
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:Linux篇–CSDN博客 文章目录 一.认识硬件--磁盘物理存储结构1.存储介质类型2.物理存储单元3…...
Tracing the thoughts of a large language model 简单理解
Tracing the thoughts of a large language model 这篇论文通过电路追踪方法(Circuit Tracing)揭示了大型语言模型Claude 3.5 Haiku的内部机制,其核心原理可归纳为以下几个方面: 1. 方法论核心:归因图与替换模型 替换模型(Replacement Model) 使用跨层转码器(CLT)将原…...
OpenCV边缘检测技术详解:原理、实现与应用
概述 边缘检测是计算机视觉和图像处理中最基本也是最重要的技术之一,它通过检测图像中亮度或颜色急剧变化的区域来识别物体的边界。边缘通常对应着场景中物体的物理边界、表面方向的变化或深度不连续处。 分类 OpenCV提供了多种边缘检测算法,下面我们介…...
Java学习——day22(Java反射基础入门)
文章目录 1.反射的定义2. 认识反射的关键API2.1 Class2.2 Field2.3 Method2.4 Constructor 3. 示例代码讲解与分析4. 编写反射示例代码的步骤4.1 定义测试类4.2 编写主程序,使用反射获取信息4.3 通过反射创建对象并调用方法 5. 总结6.今日生词 Java反射笔记 1.反射的…...
BN 层做预测的时候, 方差均值怎么算
✅ 一、Batch Normalization(BN)回顾 BN 层在训练和推理阶段的行为是不一样的,核心区别就在于: 训练时用 mini-batch 里的均值方差,预测时用全局的“滑动平均”均值方差。 🧪 二、训练阶段(Trai…...
JS 其他事件类型
页面加载 事件 window.addEvent() window.addEventListener(load,function(){const btn document.querySelector(button)btn.addEventListener(click,function(){alert(按钮)})})也可以给其他标签加该事件 HTML加载事件 找html标签 也可以给页面直接赋值...
AI Agent设计模式五:Orchestrator
概念 :中央任务调度中枢 ✅ 优点:全局资源协调,确保任务执行顺序❌ 缺点:单点故障风险,可能成为性能瓶颈 import operator import osfrom langchain.schema import SystemMessage, HumanMessage from langchain_opena…...
