动态渲染可编辑单元格的Table
一、问题描述
问题是这样的,后台传了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实现方式。如有问题欢迎留言批评指正,谢谢!
推荐阅读