在 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 組件有什么優化建議?歡迎評論交流!
🔥 如果覺得有幫助,別忘了點贊 + 收藏! 🎯