一、問題描述
問題是這樣的,后台傳了xArr = [x1, x2,...,xn]和yArr = [y1, y2, ..yn]兩個數組,前端要渲染出表格並且可以填寫每個單元格的值,然后按照一定數據結構保存並傳給后台,並且再次獲取這個數據結構和數組xArr、yArr可以自己渲染出這個表?實現新增和修改的功能。大致界面效果如下圖所示:

y1, y2,...,yn作為列名,x1,x2, ..., xn作為第一列數據,此業務模型是一種常見的表格,只不過要求行列都不固定,由后台數據提供並且動態生成。還要能夠實現修改功能。本質上是一個動態渲染可編輯Table的問題。難點在於動態構建表格並且實現數據展示和保存。
二、解決思路
(1)數據轉換成表格后,處理起來就簡單了,如果以常見的Table組件為例,只需要構建columns和dataSource兩個數組數據即可渲染出表格;
(2)渲染出表格后,表格每一個余下的單元格都要可輸入,可以考慮單元格利用render渲染出Input組件,通過Input的操作onChange或onBlur去改變數據並存儲。
(3)數組是引用類型,可以利用引用類型只要沒有深拷貝或改變指針指向內存地址就不變的原理,方便記錄操作后的數據。
三、解決方法(以React結合ant design UI的Table組件為例):
(1)動態構建columns(表格列數據)和dataSource(表格數據源)渲染出表格。(Table可參考 https://ant.design/components/table-cn/#header)
1 const xArr = ['x1', 'x2', 'x3', 'x4']; 2 const dataSource = xArr.map((v, i) => ({ 3 key: String(i),//此處自定義表格每一行的唯一key,如果沒有設置唯一標志會報錯 4 y0: v,//第一列數據即顯示X1-Xn的那一列 5 })); 6 7 const yArr = ['y1', 'y2', 'y3', 'y4', 'Y5']; 8 const columns = [{ 9 title: ' ', 10 dataIndex: 'y0',//第一列y0為列的dataIndex,用於顯示x1-xn 11 }, ...yArr.map(item => ({//其他列通過yArr循環得到,並用...解構直接合並為columns 12 title: item, 13 dataIndex: item, 14 }))];
這樣就得到形如dataSource = [{ key: '0', y0:'x1'}, { key: '0', y0:'x1'},...]; columns = [{ title: '', dataIndex: 'y0'},{ title: 'y1', dataIndex: 'y1'},...];的表格數據,將此數據源傳入表格組件Table,即可渲染出表格如下:
<Table columns={columns} dataSource={dataSource} />

(2)表格添加Input並且根據onChange/onBlur事件動態記錄dataSource的變化。
1 const columns = [{ 2 title: ' ', 3 dataIndex: 'y0', 4 }, ...yArr.map(item => ({ 5 title: item, 6 dataIndex: item, 7 render: (text, record) => ( 8 <Input defaultValue={record[item]} onChange={(e) => { record[item] = e.target.value; }} /> 9 ), 10 }))];
渲染效果如下:

四、完整代碼
/**
* @author xiao-pengyou
* @create date 2019-03-27
* @desc 動態可編輯表格
* */
import React, { PureComponent } from 'react';
import { Table, Input } from 'antd';
export default class Demo extends PureComponent {
state = { dataSource: [] };
componentDidMount() {
const xArr = ['x1', 'x2', 'x3', 'x4'];
const dataSource = xArr.map((v, i) => ({key: String(i),y0: v}));
this.setState({ dataSource });//dataSource不能在render里面構建,在render里面構建每次重新渲染的時候dataSource會被重新構建,指針指向變化導致先前的修改不能被跟蹤
}
render() {
const yArr = ['y1', 'y2', 'y3', 'y4', 'y5'];
const that = this;//定義中間量that=this確保columns內部onChange事件作用域為當前組件,方便調用forceUpdate()強制渲染表格
const columns = [{
title: ' ',
dataIndex: 'y0',
}, ...yArr.map(item => ({
title: item,
dataIndex: item,
render: (text, record) => (
<Input value={record[item]} onChange={(e) => { record[item] = e.target.value; that.forceUpdate(); }} />
),
}))];//最終的dataSource就是我們想要的數據結構,修改時直接把這個dataSource傳給構建的表格就可以渲染
return <Table columns={columns} dataSource={this.state.dataSource} bordered pagination={false} />;//bordered設置邊框,pagination=false取消分頁功能,可以不用在意此參數
}
}
最終效果(控制台輸出為提交給后台的dataSource數組):

以上就是一個動態列的可編輯表格的React實現方式。如有問題歡迎留言批評指正,謝謝!
本文為原創博客,非法抄襲或復制將追究法律責任,轉載請注明出處:https://www.cnblogs.com/xiao-pengyou/
