一、前言
antd的table,默认是点击左边的单选/复选按钮,才能选中一行数据;
现在想实现点击右边的部分,也可以触发操作选中这行数据。
可以使用onRow
实现,样例如下。
二、代码
1.表格样式部分
//表格table样式部分
{isRadio ?
<Table
dataSource={data.list}
onRow={(record) => ({
onClick: () => {
this.selectRow(record);
},
})}
rowSelection={{
type: 'radio',
selectedRowKeys: selectedIdsInSearchTab,
onChange: this.onSelectChange,
}} // 表格是否可复选,加type是单选,去掉是多选
columns={this.getColumns()}
rowKey={record => record.id}
pagination={false}
loading={loading}
size="middle"
bordered
scroll={{ x: 1100 }}
/>
:
<Table
dataSource={data.list}
onRow={(record) => ({
onClick: () => {
this.selectRow(record);
},
})}
rowSelection={{
selectedRowKeys: selectedIdsInSearchTab,
onChange: this.onSelectChange,
onSelect: this.onSelect,
onSelectAll: this.onSelectAll,
}} // 表格是否可复选,加type是单选,去掉是多选
columns={this.getColumns()}
rowKey={record => record.id}
pagination={false}
loading={loading}
size="middle"
bordered
scroll={{ x: 1100 }}
/>
}
说明:
(1)isRadio 是自己写的一个变量,用来区分是单选表格还是多选表格
(2)onRow
的this.selectRow(record)
方法是核心,用来实现点击一行数据即可选中(其实是点击 单选/多选按钮
右边的部分时,触发这个方法)
(3)onChange: this.onSelectChange,
这个方法是点击左边的单选/多选按钮
时,会触发;
但是由于框架自身bug,翻页多选数据的话,id数组没有问题、内容数组会只保留当前页、无法保留前几页选中的内容;
所以多选时增加了onSelect
和onSelectAll
方法,可以解决这个问题。
(4)加上 type: 'radio'
,表格就会展示为单选按钮;去掉,表格默认展示为多选按钮
(5)selectedRowKeys: selectedIdsInSearchTab
,这个是保存选中行id的一个数组,必须加,数组有内容后,页面就会显示出哪行被选中的样式
2.onRow
的this.selectRow(record)
方法
selectRow = (record) => {
const {
dispatch,
TrainPlanManage_SelectBscUserT: { selectedIdsInSearchTab,selectedRowsInSearchTab },
isRadio
} = this.props;
//如果是单选
if(isRadio){
//获取存放的key
const selectedRowKeys = [record.id];
//获取存放的数据value
const selectedRows = [record];
dispatch({
type: 'TrainPlanManage_SelectBscUserT/updateSelectedIdsInSearchTab',
selectedIds : selectedRowKeys,
selectedRows: selectedRows,
});
}
//否则是多选
else{
//获取存放的key
const selectedRowKeys = [...selectedIdsInSearchTab];
//获取存放的数据value
const selectedRows = [...selectedRowsInSearchTab];
if (selectedRowKeys.indexOf(record.id) >= 0) {
//当点击选中的数据,取消选中
selectedRowKeys.splice(selectedRowKeys.indexOf(record.id), 1);
//取消选中也要删除数组中的value
selectedRows.forEach((element,index) => {
if(element.id === record.id){
//根据id获取到数组里当前数据的下标,并删除。
selectedRows.splice(index,1)
}
});
} else {
selectedRowKeys.push(record.id);
//将选中的数据加入数组里
selectedRows.push(record)
}
//this.setState({ selectedRowKeys,selectedRows });
dispatch({
type: 'TrainPlanManage_SelectBscUserT/updateSelectedIdsInSearchTab',
selectedIds : selectedRowKeys,
selectedRows: selectedRows,
});
}
}
说明:
(1)TrainPlanManage_SelectBscUserT: { selectedIdsInSearchTab,selectedRowsInSearchTab }
的意思是,从TrainPlanManage_SelectBscUserT.js
里拿出2个变量来,selectedIdsInSearchTab
是保存被选中id的数组,selectedRowsInSearchTab
是保存被选中整行数据的数组
(2)入参record
,就是当前点击的行数据,单选时直接保存回那2个变量中即可;
多选时,先判断现有数组中是否存在当前点击行的id,如果存在,那就是取消选择的意思,从数组移除内容;
如果不存在,那就是新增,直接放入数组。
(3)selectedRows.splice(index,1)
的意思是,从数组中删除下标为index的数据。
(4)dispatch
方法,调用的是TrainPlanManage_SelectBscUserT.js
里的方法,把处理好的数组保存进去用,如下:
export default {
namespace: 'TrainPlanManage_SelectBscUserT',
state: {
selectedIdsInSearchTab:[],
selectedRowsInSearchTab:[],
......
---------------------------------------
reducers: {
updateSelectedIdsInSearchTab(state, action) {
return {
...state,
selectedIdsInSearchTab: action.selectedIds || state.selectedIds,
selectedRowsInSearchTab: action.selectedRows || state.selectedRows,
};
},
}
(5)如果变量在同一个js中,也可以使用//this.setState({ selectedRowKeys,selectedRows });
来保存。
3.onChange: this.onSelectChange
方法
这个方法是点击左边的 单选/复选
按钮 触发的;
单选没有问题;
多选有问题,上方提到了,不过自己把onSelect
和onSelectAll
方法加上,就可以解决问题,后续会有。
代码如下:
// 复选框选中后的方法
onSelectChange = (selectedIds, selectedRows) => {
const {
dispatch,
TrainPlanManage_SelectBscUserT: { selectedIdsInSearchTab,selectedRowsInSearchTab },
isRadio
} = this.props;
//如果是单选
if(isRadio){
//和原来保持一致
dispatch({
type: 'TrainPlanManage_SelectBscUserT/updateSelectedIdsInSearchTab',
selectedIds,
selectedRows,
});
}
//否则是多选
else{
//这里管选中的行,都放到这个数组里
if(selectedRowsInSearchTab !== null && selectedRowsInSearchTab !== '' && selectedRowsInSearchTab !== undefined) {
for(let index in selectedRows){
let flag = false;
let id = selectedRows[index].id;
for(let i in selectedRowsInSearchTab){
if(selectedRowsInSearchTab[i].id === id){
flag = true;
}
}
if(!flag){
selectedRowsInSearchTab.push(selectedRows[index]);
}
}
}
//然后放回去
dispatch({
type: 'TrainPlanManage_SelectBscUserT/updateSelectedIdsInSearchTab',
selectedIds,
selectedRows: selectedRowsInSearchTab,
});
}
};
说明:
(1) 这个方法入参是选中行的id数组和选中行的数据数组。
(2)dispatch
方法与上方相同,就是把数组直接保存进去。
(3)多选时,主要负责把多选的行保存进去,有去重。(解决框架翻页多选后只有当前行数据、没有之前页选中行数据的问题)
4.onSelect: this.onSelect
方法
这个是点击列表左边部分的方框会触发的方法(点击右边的行部分不会触发)
代码如下:
onSelect = (record,selected,selectedRows,nativeEvent) => {
const {
dispatch,
TrainPlanManage_SelectBscUserT: { selectedIdsInSearchTab,selectedRowsInSearchTab },
isRadio
} = this.props;
//如果取消选择,那就删掉数组元素
if(selectedRowsInSearchTab !== null && selectedRowsInSearchTab !== '' && selectedRowsInSearchTab !== undefined){
if(!selected){
for(const index in selectedRowsInSearchTab){
if(record.id === selectedRowsInSearchTab[index].id){
selectedRowsInSearchTab.splice(index,1);
}
}
}
}
}
说明:
这个负责取消选中行时,把行元素从数组中移除。(选中行时onChange负责装入元素了,这里不用管)
5.onSelect: this.onSelectAll
方法
这个是点击列表左上方的全选方框会触发的方法
代码如下:
onSelectAll = (selected,selectedRows,changeRows) => {
const {
dispatch,
TrainPlanManage_SelectBscUserT: { selectedIdsInSearchTab,selectedRowsInSearchTab },
isRadio
} = this.props;
//如果取消选择,那就删掉数组元素
if(selectedRowsInSearchTab !== null && selectedRowsInSearchTab !== '' && selectedRowsInSearchTab !== undefined){
if(!selected){
for(const i in changeRows){
let record = changeRows[i];
for(const index in selectedRowsInSearchTab){
if(record.id === selectedRowsInSearchTab[index].id){
selectedRowsInSearchTab.splice(index,1);
}
}
}
}
}
}
说明:
这个负责取消选中行时,把行元素从数组中移除。(选中行时onChange负责装入元素了,这里不用管)
三、总结
1.这个方法可以实现点击表格行选中一行数据。
2.这个方法解决了翻页后、选中行数组丢失之前页的选中行、只保留当前页选中行的问题。(点击左边的选择框和右边的行都可以正常使用)
3.需要自己写onRow、onChange、onSelect、onSelectAll这4个方法
4.onRow实现点击行可以选中/取消选中本行;onChange负责点击左边按钮把选中数据放入数组;onSelect/onSelectAll负责点左边按钮取消选中时把数据从数组中移除。
5.打印日志发现,框架先执行onChange,后执行onSelect,不影响数据的放入/移除数组。(后续优化的话,应该可以把放入/移除操作写到一个方法里?比如都写onSelect里面)
四、备注
1.发现,rowKey={record => record.id}
这个东西,是配置返回列表的哪个字段作为table中元素的id;如果列表返回有id的话,把id装入selectedRowKeys: selectedIdsInSearchTab
中的selectedIdsInSearchTab数组,页面就会显示哪些行被选中;
但是如果数据列表没有叫id的字段,那么把其它值装入绑定数组selectedIdsInSearchTab没有效果,页面不知道选中的是哪行;
如果打印onChange
里的selectedIds
数组,会发现框架自己默认生成了一个数组当做了该行的id(比如0,1,2),后续用于实现选中行效果等。
所以,如果数据列表没有叫id的字段,那就修改rowKey={record => record.myid}
这个东西,找到一个唯一值作为id才行。