[特殊字符] 使用 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 組件有什么優化建議?歡迎評論交流!

🔥 如果覺得有幫助,別忘了點贊 + 收藏! 🎯

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/74767.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/74767.shtml
英文地址,請注明出處:http://en.pswp.cn/web/74767.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

0302useState-hooks-react-仿低代碼平臺項目

文章目錄 1 useState1.1 說明返回 1.2 示例1.3 數據類型 2 state2.1 概述2.2 state特點 3 state重構問卷4 immer結語 1 useState useState 是一個 React Hook&#xff0c;它允許你向組件添加一個 狀態變量。 1.1 說明 語法 const [state, setState] useState(initialState…

前端實現單點登錄(SSO)的方案

概念&#xff1a;單點登錄&#xff08;Single Sign-On, SSO&#xff09;主要是在多個系統、多個瀏覽器或多個標簽頁之間共享登錄狀態&#xff0c;保證用戶只需登錄一次&#xff0c;就能訪問多個關聯應用&#xff0c;而不需要重復登錄。 &#x1f4a1; 方案分類 1. 前端級別 SS…

zabbix監控網站(nginx、redis、mysql)

目錄 前提準備&#xff1a; zabbix-server主機配置&#xff1a; 1. 安裝數據庫 nginx主機配置&#xff1a; 1. 安裝nginx redis主機配置&#xff1a; 1. 安裝redis mysql主機配置&#xff1a; 1. 安裝數據庫 zabbix-server&#xff1a; 1. 安裝zabbix 2. 編輯配置文…

無人機等非合作目標公開數據集2025.4.3

一.無人機遙感數據概述 1.1 定義與特點 在遙感技術的不斷發展中&#xff0c;無人機遙感數據作為一種新興的數據源&#xff0c;正逐漸嶄露頭角。它是通過無人駕駛飛行器&#xff08;UAV&#xff09;搭載各種傳感器獲取的地理空間信息&#xff0c;具有 覆蓋范圍大、綜合精度高、…

大數據時代的隱私保護:區塊鏈技術的創新應用

一、引言 在當今數字化時代&#xff0c;大數據已經成為推動社會發展的關鍵力量。從商業決策到社會治理&#xff0c;從醫療健康到金融服務&#xff0c;數據的價值日益凸顯。然而&#xff0c;隨著數據的大量收集和廣泛使用&#xff0c;隱私保護問題也日益突出。如何在充分利用大…

LeetCode 2442:統計反轉后的不同整數數量

目錄 核心思想&#xff1a;數字的“拆分”與“重組” 分步拆解&#xff08;以輸入 123 為例&#xff09; 關鍵操作詳解 為什么能處理中間或末尾的0&#xff1f; 數學本質 總結 題目描述 解題思路 代碼實現 代碼解析 復雜度分析 示例演示 總結 核心思想&#xff1a;…

Python爬蟲第3節-會話、Cookies及代理的基本原理

目錄 一、會話和Cookies 1.1 靜態網頁和動態網頁 1.2 無狀態HTTP 1.3 常見誤區 二、代理的基本原理 2.1 基本原理 2.2 代理的作用 2.3 爬蟲代理 2.4 代理分類 2.5 常見代理設置 一、會話和Cookies 大家在瀏覽網站過程中&#xff0c;肯定經常遇到需要登錄的場景。有些…

Flutter項目之登錄注冊功能實現

目錄&#xff1a; 1、頁面效果2、登錄兩種狀態界面3、中間按鈕部分4、廣告區域5、最新資訊6、登錄注冊頁聯調6.1、網絡請求工具類6.2、注冊頁聯調6.3、登錄問題分析6.4、本地緩存6.5、共享token6.6、登錄頁聯調6.7、退出登錄 1、頁面效果 import package:flutter/material.dart…

木馬學習記錄

一句話木馬是什么 一句話木馬就是僅需要一行代碼的木馬&#xff0c;很簡短且簡單&#xff0c;木馬的函數將會執行我們發送的命令 如何發送命令&#xff06;發送的命令如何執行? 有三種方式&#xff1a;GET&#xff0c;POST&#xff0c;COOKIE&#xff0c;一句話木馬中用$_G…

(C語言)單鏈表(1.0)(單鏈表教程)(數據結構,指針)

目錄 1. 什么是單鏈表&#xff1f; 2. 單鏈表的代碼表示 3. 單鏈表的基本操作 3.1 初始化鏈表 3.2 插入結點&#xff08;頭插法&#xff09; 3.3 插入結點&#xff08;尾插法&#xff09; 3.4 遍歷鏈表 4. 單鏈表的優缺點 代碼&#xff1a;*L(LinkList)malloc(sizeof(…

Sentinel-自定義資源實現流控和異常處理

目錄 使用SphU的API實現自定義資源 BlockException 使用SentinelResource注解定義資源 SentinelResourceAspect 使用Sentinel實現限流降級等效果通常需要先把需要保護的資源定義好&#xff0c;之后再基于定義好的資源為其配置限流降級等規則。 Sentinel對于主流框架&#…

Linux信號處理解析:從入門到實戰

Linux信號處理全解析&#xff1a;從入門到實戰 一、初識Linux信號&#xff1a;系統級的"緊急電話" 信號是什么&#xff1f; 信號是Linux系統中進程間通信的"緊急通知"&#xff0c;如同現實中的交通信號燈。當用戶按下CtrlC&#xff08;產生SIGINT信號&…

Java的Selenium的特殊元素操作與定位之select下拉框

如果頁面元素是一個下拉框&#xff0c;我們可以將此web元素封裝為Select對象 Select selectnew Select(WebElement element); Select對象常用api select.getOptions();//獲取所有選項select.selectBylndex(index);//根據索引選中對應的元素select.selectByValue(value);//選…

藍橋云客 刷題統計

刷題統計 問題描述 小明決定從下周一開始努力刷題準備藍橋杯競賽。他計劃周一至周五每天做 a 道題目&#xff0c;周六和周日每天做 b 道題目。請你幫小明計算&#xff0c;按照計劃他將在第幾天實現做題數大于等于 n 題&#xff1f; 輸入格式 輸入一行包含三個整數 a, b 和 …

三防筆記本有什么用 | 三防筆記本有什么特別

在現代社會&#xff0c;隨著科技的不斷進步&#xff0c;筆記本電腦已經成為人們工作和生活的重要工具。然而&#xff0c;在一些特殊的工作環境和極端條件下&#xff0c;普通筆記本電腦往往難以滿足需求。這時&#xff0c;三防筆記本以其獨特的設計和卓越的性能&#xff0c;成為…

智能體和RPA都需要程序思維,如何使用影刀的變量?

歡迎來到濤濤聊AI&#xff0c; 不管AI還是RPA&#xff0c;都需要用到編程思想才能完成批量工作。今天研究了下影刀的變量。 變量類型 根據變量值選擇相應的類型&#xff0c;可選擇任意一種影刀所支持的數據類型 變量值 指定變量中保存的值&#xff0c;會根據不同的類型設置…

【藍橋杯】算法筆記3

1. 最長上升子序列(LIS) 1.1. 題目 想象你有一排數字,比如:3, 1, 2, 1, 8, 5, 6 你要從中挑出一些數字,這些數字要滿足兩個條件: 你挑的數字的順序要和原來序列中的順序一致(不能打亂順序) 你挑的數字要一個比一個大(嚴格遞增) 問:最多能挑出多少個這樣的數字? …

性能測試之jmeter的基本使用

簡介 Jmeter是Apache的開源項目&#xff0c;基于Java開發&#xff0c;主要用于進行壓力測試。 優點&#xff1a;開源免費、支持多協議、輕量級、功能強大 官網&#xff1a;https://jmeter.apache.org/index.html 安裝 安裝步驟&#xff1a; 下載&#xff1a;進入jmeter的…

【NLP 面經 7、常見transformer面試題】

目錄 1. 為何使用多頭注意力機制&#xff1f; 2. Q和K使用不同權重矩陣的原因 3. 選擇點乘而非加法的原因 4. Attention進行scaled的原因 5. 對padding做mask操作 6. 多頭注意力降維原因 7. Transformer Encoder模塊簡介 8. 乘以embedding size的開方的意義 9. 位置編碼 10. 其…

【深度學習】CNN簡述

文章目錄 一、卷積神經網絡&#xff08;CNN&#xff09;二、CNN結構特性1. CNN 典型結構2. 局部連接3. 權重共享4.空間或時間上的次采樣 三、理解層面 一、卷積神經網絡&#xff08;CNN&#xff09; 卷積神經網絡(Convolutional Neural Network&#xff0c;CNN)是一種用于處理…