轉帖|使用教程|編輯:龔雪|2022-11-02 10:11:12.607|閱讀 262 次
概述:本文將為大家介紹如何在React中使用SpreadJS直接在頁面端導入和導出 Excel 文件,歡迎下載相關組件體驗~
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
公司近期接到一個客戶的來電咨詢,具體需求點僅僅提到支持雙擊填報、具備邊框設置、背景色設置和刪除行列等功能,但這部分需求描述不是很明確,而且最后提到“像Excel的類似體驗”。經過與客戶的業務需求方的直接溝通,可以確認終端用戶就是想直接在網頁端操作Excel,并且直接把編輯完成的表格以Excel的格式下載到本地。
SpreadJS為React開發人員提供了其他任何地方都很難找到的電子表格功能。有很多業務線應用程序可以從嵌入交互式電子表格,而不是僅僅使用枯燥的靜態表格中受益——但這些枯燥的表格是業務應用程序最終的結果,因為開發人員沒有意識到,其實有更好的選擇。
在本文中,我們將利用SpreadJS的內置 Excel 導入/導出功能來實現上述需求。
你可以看到在 StackBlitz 上實時運行的靜態表格應用程序,并且可以在此處找到演示源。
如果你想要已經添加了 SpreadJS 的成熟應用程序,請。
完成后,打開終端,導航到克隆存儲庫的目錄,然后運行:
> npm install
現在你將看到更新后的應用程序正在運行。
Step 1: 原生HTML表格
該應用程序的前端基于 ReactJS 構建,并由使用 JSX 語法、JavaScript 和 HTML 代碼組合創建的組件構成。該應用程序是使用功能組件的語法創建的。這種方法使我們可以避免編寫類,這會使組件更加復雜和難以閱讀。
儀表板位于 JSX 組件層次結構的頂部。它呈現 HTML 內容并維護應用程序狀態,源自具有虛擬 JSON 銷售數據的文件。
每個子組件負責呈現其內容。由于只有 Dashboard 保存應用程序狀態,因此它通過 props 將數據向下傳遞給每個子組件。
Import React, { useState } from ‘react’; import { NavBar } from ‘./NavBar’ import { TotalSales } from ‘./TotalSales’ import { SalesByCountry } from ‘./SalesByCountry’ import { SalesByPerson } from ‘./SalesByPerson’ import { SalesTable } from ‘./SalesTable’ import { groupBySum } from “../util/util”; import { recentSales } from “../data/data”; export const Dashboard = () => { const sales = recentSales; function totalSales() { const items = sales; const total = items.reduce( (acc, sale) => (acc += sale.value), 0 ); return parseInt(total); }; function chartData() { const items = sales; const groups = groupBySum(items, “country”, “value”); return groups; }; function personSales() { const items = sales; const groups = groupBySum(items, “soldBy”, “value”); return groups; }; function salesTableData() { return sales; }; return ( <div style={{ backgroundColor: ‘#ddd’ }}> <NavBar title=”Awesome Dashboard” /> <div className=”container”> <div className=”row”> <TotalSales total={totalSales()}/> <SalesByCountry salesData={chartData()}/> <SalesByPerson salesData={personSales()}/> <SalesTable tableData={salesTableData()}/> </div> </div> </div> ); }
Step 2: 替換為SpreadJS表格
在編寫任何代碼行之前,我們必須首先安裝 GrapeCity 的 Spread.Sheets Wrapper Components for React。只需停止應用程序,然后運行以下兩個命令:
> npm install @grapecity/spread-sheets-react
> npm start
在使用SpreadJS之前,你必須修改 SalesTable.js 文件以聲明 GrapeCity 組件的導入。這些導入將允許訪問 SpreadSheets、Worksheet 和 SpreadJS 庫的 Column 對象。
Import React from ‘react’; import { TablePanel } from “./TablePanel”; // SpreadJS imports import ‘@grapecity/spread-sheets-react’; /* eslint-disable */ import “@grapecity/spread-sheets/styles/gc.spread.sheets.excel2016colorful.css”; import { SpreadSheets, Worksheet, Column } from ‘@grapecity/spread-sheets-react’;
此外,如果沒有一些基本設置,SpreadJS 工作表將無法正常工作,因此讓我們創建一個配置對象來保存工作表參數。
Export const SalesTable = ({ tableData } ) => { const config = { sheetName: ‘Sales Data’, hostClass: ‘ spreadsheet’, autoGenerateColumns: false, width: 200, visible: true, resizable: true, priceFormatter: ‘$ #.00’, chartKey: 1 }
首先,我們必須消除在 SalesTable 組件中呈現靜態面板的 JSX 代碼:
return ( <TablePanel title=”Recent Sales”> <table className=”table”> <thead> <tr> <th>Client</th> <th>Description</th> <th>Value</th> <th>Quantity</th> </tr> </thead> <tbody> {tableData.map((sale) => (<tr key={sale.id}> <td>{sale.client}</td> <td>{sale.description}</td> <td>${sale.value}</td> <td>{sale.itemCount}</td> </tr>))} </tbody> </table> </TablePanel> );
通過消除這個代碼塊,我們最終只得到了 TablePanel,這是我們在每個組件中使用的通用 UI 包裝器。
Return ( <TablePanel title=”Recent Sales”> </TablePanel> );
此時,我們現在可以在 TablePanel 中插入 SpreadJS SpreadSheets 組件。請注意,SpreadSheets 組件可能包含一個或多個工作表,就像 Excel 工作簿可能包含一個或多個工作表一樣。
Return ( <TablePanel key={config.chartKey} title=”Recent Sales”> <SpreadSheets hostClass={config.hostClass}> <Worksheet name={config.sheetName} dataSource={tableData} autoGenerateColumns={config.autoGenerateColumns}> <Column width={50} dataField=’id’ headerText=”ID”></Column> <Column width={200} dataField=’client’ headerText=”Client”></Column> <Column width={320} dataField=’description’ headerText=”Description”></Column> <Column width={100} dataField=’value’ headerText=”Value” formatter={config.priceFormatter} resizable=”resizable”></Column> <Column width={100} dataField=’itemCount’ headerText=”Quantity”></Column> <Column width={100} dataField=’soldBy’ headerText=”Sold By”></Column> <Column width={100} dataField=’country’ headerText=”Country”></Column> </Worksheet> </SpreadSheets> </TablePanel> );
作為畫龍點睛的一筆,我們將以下這些行添加到 App.css 文件中以修復電子表格的尺寸,以便該組件占據底部面板的整個寬度和銷售儀表板頁面的適當高度。
/*SpreadJS Spreadsheet Styling*/ .container.spreadsheet { width: 100% !important; height: 400px !important; border: 1px solid lightgray !important; padding-right: 0; padding-left: 0;
這為我們提供了下面令人驚嘆的電子表格:
請注意,SpreadJS 工作表如何為我們提供與 Excel 電子表格相同的外觀。
在 Worksheet 組件中,我們可以看到 Column 組件,它定義了每一列的特征,例如寬度、綁定字段和標題文本。我們還在銷售價值列中添加了貨幣格式。
與舊的靜態表一樣,新的 SpreadJS 電子表格組件從儀表板傳遞的道具接收數據。如你所見,電子表格允許你直接更改值,就像在 Excel 電子表格中一樣。但是,正如你對 React 應用程序所期望的那樣,這些更改不會自動反映在其他組件中。為什么呢?
從儀表板接收數據后,SpreadJS 工作表開始使用副本,而不是儀表板組件中聲明的銷售數據。事件和函數應該處理任何數據修改以相應地更新應用程序的狀態。
對于下一個任務,你必須使應用程序反映對所有 Dashboard 組件上的 SpreadJS 工作表所做的更改。
Step 3: SpreadJS實現響應式數據綁定
目前,在 Dashboard.js 文件中聲明的銷售常量負責維護應用程序的狀態。
Const sales = recentSales;
正如我們所看到的,這種結構意味著靜態數據,阻止了我們希望實現的動態更新。因此,我們將用稱為鉤子的賦值替換那行代碼。在 React 中,鉤子具有簡化的語法,可以同時提供狀態值和處理函數的聲明。
Const[sales, setSales] = new useState(recentSales);
上面的代碼行顯示了 JavaScript 數組解構語法。 useState 函數用于聲明銷售常量,它保存狀態數據,以及 setSales,它引用僅在一行中更改銷售數組的函數。
但是,我們的應用程序中還不存在這個 useState 函數。我們需要從 Dashboard.js 組件文件開頭的 React 包中導入它:
import React, { useState } from ‘react’;
現在,我們準備在必要時更新 sales 數組的狀態。
我們希望將對工作表所做的更改傳播到儀表板的其余部分。因此,我們必須訂閱一個事件來檢測對 Worksheet 組件單元格所做的更改,并在 SalesTable.js 文件中實現相應的事件處理。
我們將此事件處理程序稱為handleValueChanged。
<SpreadSheets hostClass={config.hostClass} valueChanged={handleValueChanged}>
我們仍然需要實現一個同名的函數。在其中,我們獲取工作表的已更改數據源數組,并將該數組傳遞給名為 valueChangeCallback 的函數。
Function handleValueChanged(e, obj) { valueChangedCallback(obj.sheet.getDataSource()); } handleValueChanged.bind(this);
然后將 valueChangedCallback 函數從 Dashboard 傳遞到 SalesTable 組件:
<SalesTable tableData={salesTableData()} valueChangedCallback={handleValueChanged}/>
現在,你必須將此回調函數作為參數傳遞給 SalesTable 組件:
export const SalesTable = ({ tableData, valueChangedCallback } ) => {
對工作表中單元格的任何更改都會觸發回調函數,該函數會執行 Dashboard 組件中的 handleValueChanged 函數。下面的handleValueChanged 函數必須在Dashboard 組件中創建。它調用 setSales 函數,該函數更新組件的狀態。因此,更改會傳播到應用程序的其他組件。
Function handleValueChanged(tableData) { setSales(tableData.slice(0)); }
你可以通過編輯一些銷售額值并查看儀表板頂部的銷售額變化來嘗試此操作:
Step 4: 實現導入導出Excel
到目前為止,我們已經了解了如何用 SpreadJS 電子表格替換靜態銷售表。我們還學習了如何通過 React 的鉤子和回調在應用程序組件上傳播數據更新。我們設法用很少的代碼提供了這些功能。你的應用程序看起來已經很棒了,并且你相信它將給你未來的客戶留下深刻印象。但在此之前,讓我們錦上添花。
你已經知道你的企業用戶在日常生活中經常使用 Excel。相同的用戶將開始在 React 和 SpreadJS 之上使用你的全新應用程序。但在某些時候,他們會錯過 Excel 和你出色的儀表板之間的集成。
如果你只能將電子表格數據導出到 Excel 并將數據從 Excel 導入到 SpreadJS,則該應用程序將更加強大。你如何實現這些功能?
讓我們再次停止應用程序并安裝 GrapeCity 的 Spread.Sheets 客戶端 Excel IO 包以及文件保護程序包:
> npm install @grapecity/spread-excelio
> npm install file-saver
> npm start
要將數據從我們的應用程序導出到 Excel 文件(擴展名為 .xlsx),我們必須修改 SalesTable 組件,聲明 Excel IO 和文件保護程序組件的導入。
Import { IO } from “@grapecity/spread-excelio”; import { saveAs } from ‘file-saver’;
接下來,我們將更改 SalesTable.js 文件的 JSX 代碼,以添加一個按鈕以將 SpreadJS 作表數據導出到本地文件。單擊該按鈕將觸發一個名為 exportSheet 的事件處理程序。
{/* EXPORT TO EXCEL */} <div className=”dashboardRow”> <button className=”btn btn-primary dashboardButton” onClick={exportSheet}>Export to Excel</button> </div> </TablePanel>
反過來,exportSheet 函數會將工作表中的數據保存到名為 SalesData.xslx 的文件中。該函數首先將 Spread 對象中的數據序列化為 JSON 格式,然后通過 Excel IO 對象將其轉換為 Excel 格式。
Function exportSheet() { const spread = _spread; const ilename = “SalesData.xlsx”; const sheet = spread.getSheet(0); const excelIO = new IO(); const json = JSON.stringify(spread.toJSON({ includeBindingSource: true, columnHeadersAsFrozenRows: true, })); excelIO.save(json, (blob) => { saveAs(blob, ilename); }, function € { al€( }); }
請注意上述函數如何需要一個展開對象,該對象必須與我們在 SalesTable 組件中使用的 SpreadJS 工作表的實例相同。一旦定義了 SpreadSheet 對象,上面清單中的 getSheet(0) 調用就會檢索電子表格數組中的第一個工作表:
const sheet = spread.getSheet(0);
但是我們如何以編程方式獲取電子表格的實例呢?
一旦電子表格對象被初始化,SpreadJS 庫就會觸發一個名為 workbookInitialized 的事件。我們必須處理它并將實例存儲為 SalesTable 組件的狀態。讓我們首先使用 useState 鉤子為電子表格實例聲明一個狀態常量:
const [_spread, setSpread] = useState({});
我們需要將 useState 函數導入到 SalesTable.js 組件文件開頭的 React 聲明中:
import React, { useState }‘from ’react';
現在我們可以聲明一個函數來處理 workbookInit 事件……
function workbookInit(sprea setSpread(spread) }
...然后將 workbookInit 事件綁定到我們剛剛創建的函數:
<SpreadSheets hostClass={config.hostClass} workbookInitialized={workbookInit} valueChanged={handleValueChanged}>
現在,“導出到 Excel”按鈕將如下所示:
現在我們來演示如何實現 Excel 數據導入。這個過程是導出的逆過程,所以讓我們從 XLSX 文件開始。
此功能的訪問點是另一個按鈕,我們需要將其添加到 SalesTable 組件的 JSX 代碼的末尾。請注意,這里我們使用不同的按鈕類型:“文件”類型的輸入元素,它產生一個選擇文件的按鈕。當文件被選中時,onChange 事件觸發 fileChangeevent 處理程序:
<div clas”Name="dashbo”rd> {/* EXPORT TO EXCE} <button clas”Name="btn btn-primary dashboard”utton" onClick={exportSheet}>Export to Excel</bu> {/* IMPORT FROM EXCE} <div> <b>Import Excel File:</b> <div> <input”type”"file" clas”Name="file”elect" onCh€e={(e) => f€Change(e)} /> </div> </div> </div>
反過來,fileChange 函數將使用 Excel IO 對象將文件導入工作表對象。在函數結束時,會觸發一個 fileImportedCallback 事件,將數據帶到 Dashboard 組件中:
functio€hange(e) { if (_spread) { const fileDom = e.target || e.srcElement; const excelIO = new IO(); const spread = _spread; const deserializationOptions = { frozenRowsAsColumnHeaders: true }; excelIO.open(fileDom.files[0], (data) => { const newSalesData = extractSheetData(data); fileImportedCallback(newSalesData }); } }
但是這個回調需要聲明為 SalesTable 組件的參數:
export const SalesTable = ({ tableData, valueChangedCallback, fileImportedCallback } ) => {
此外,我們必須通過從 util.js 文件中導入來為 SalesTable 組件提供 extractSheetData 函數:
import { extractSh“etData } from "”./util/util.js";
我們需要為 Dashboard 組件上的保存文件實現事件處理程序。這個函數唯一要做的就是使用來自 SpreadJS 工作表的數據更新儀表板的狀態。
function handleFileImportewSales) { setSales(newSales.slice(0)); } <SalesTable tableData={saleleData()} valueChangedCallback={handleValueChanged} fileImportedCallback={handleFileImported}/>
只需幾個簡單的步驟,我們就可以將帶有靜態數據的無聊應用程序變成以具有 Excel 導入和導出功能的電子表格為中心的響應式應用程序。最后,你查看客戶的請求并驗證你的應用程序是否滿足所有要求!
我們可以擴展這些想法并為我們的應用程序探索其他令人興奮的功能。例如,我們可以自動、靜默地保存工作表數據,從而在需要時保留更改日志和回滾錯誤到表中。
此外,你可以使用 SpreadJS 事件將表格數據與遠程數據庫同步?;蛘吣憧梢詫崿F一個保存按鈕,通過 Web 服務方法將表數據復制到外部系統。
本文內容源自
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自: