Ant design vue table 单击行选中 勾选checkbox教程

最近了解Ant design 设计table 单击行选中checkedbox功能,相比于element的 @row-click 再触发toggleRowSelection,ant design的api就没那么清晰了,言归正传

期望:Ant design table 单击行选中 勾选checkedbox

实现:

单选:

onClickRow(record) {

return {

on: {

click: () => {

let keys = [];

keys.push(record.id);

this.selectedRowKeys = keys;

}

}

}

}

多选:

onClickRowMulti(record) {

return {

on: {

click: () => {

let rowKeys=this.selectedRowKeys

if(rowKeys.length>0 && rowKeys.includes(record.id)){

rowKeys.splice(rowKeys.indexOf(record.id),1)

}else{

rowKeys.push(record.id)

}

this.selectedRowKeys = rowKeys;

}

}

}

}

补充知识:使用Ant Design的Table和Checkbox模拟Tree

一、小功能大需求

先看下设计图:

需求如下:

1、一级选中(取消选中),该一级下的二级全部选中(取消选中)

2、二级全选,对应的一级选中,二级未全选中,对应的一级不选中

3、支持搜索,只搜索二级数据,并且只展示搜索到的数据以及对应的一级title,如:搜索“店员”,此时一级只展示咖啡厅....其他一级隐藏,二级只展示店员,其他二级隐藏

4、搜索出来的数据,一级不可选中,即不允许全选,搜索框清空时,回归初始化状态

5、搜索后,自动展开所有二级,默认情况下收起所有二级

看到图的时候,第一反应就是使用Tree就能搞定,但是翻阅了文档后,发现Tree并不能全部完成,所以就只能使用其他组件进行拼装,最后发现使用Table和Checkbox可以完美实现。

二、逐步完成需求

如果不想看这些,可直接到最后,有完整代码。。。。。。

1、页面构建

这个就不用多说,只是一个简单的Table嵌套Checkbox,具体可去查看文档,直接贴代码,因为是布局,所有可以忽略代码中的事件。

注意一点:因为搜索时,会改变数据,所以需要将初始化的数据进行保存。

import React, { useState, useRef, useEffect } from "react";

import { Table, Input, Checkbox } from "antd";

const { Search } = Input;

export default () => {

const initialData: any = useRef([]); //使用useRef创建initialData

const [data, setData] = useState([

{

key: 1,

title: "普通餐厅(中餐/日料/西餐厅)",

checkboxData: [

{ key: 12, title: "普通服务员" },

{ key: 13, title: "收银" },

{ key: 14, title: "迎宾/接待" },

],

},

{

key: 2,

title: "零售/快消/服装",

checkboxData: [

{ key: 17, title: "基础店员" },

{ key: 19, title: "收银员" },

{ key: 20, title: "理货员" },

],

},

]);

useEffect(() => {

initialData.current = [...data]; //设置初始化值

}, []);

const [checkedJob, setCheckedJob] = useState([]); //设置子级中选择的类

const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]); //设置选择的行

const expandedRowRender = (record: any) => {

return (

<div style={{ paddingLeft: 50, boxSizing: "border-box" }}>

<p>请选择岗位,或勾选类别全选岗位</p>

<div>

<Checkbox.Group value={checkedJob}>

{record.checkboxData.map((item: any) => {

return (

<Checkbox

value={item.key}

key={item.key}

onChange={checkChange}

>

{item.title}

</Checkbox>

);

})}

</Checkbox.Group>

</div>

</div>

);

};

const rowSelection = {

selectedRowKeys,

};

return (

<div

style={{

background: "#fff",

padding: 24,

boxSizing: "border-box",

width: 982,

}}

>

<Search

placeholder="请输入岗位名称"

onSearch={(value) => {

console.log(loop(value));

}}

/>

<Table

showHeader={false}

columns={columns}

expandable={{

expandedRowRender,

}}

dataSource={data}

pagination={false}

rowSelection={rowSelection}

/>

</div>

);

};

const columns = [{ title: "title", dataIndex: "title", key: "title" }];

2、一级选中(取消全选)

当一级选中(取消全选)时,需要更新对应二级选项的状态。在antd文档中,使用rowSelection的onSelect,可以设置选择/取消选择某行的回调。

onSelect:(record,selected)=> record:操作当前行的数据,selected:true:全选,false:取消全选

注意:当全选时,不能直接添加当前一级下的所有二级,需要过滤掉当前已经选中的二级

具体逻辑如下代码:

//首选在rowSelection配置中添加onSelectconst rowSelection = {

selectedRowKeys,

onSelect

};

//一级全选或者取消的逻辑

const onSelect = (record: any, selected: any) => {

//因为存在搜索,所以需要使用我们的初始化数据,找到当前record.key在初始化数据中对应的数据

let initialParent = initialData.current.find(

(d: any) => d.key === record.key

);  //初始化数据中对应的二级数据

let selectParentData = initialParent.checkboxData

? initialParent.checkboxData.map((d: any) => d.key)

: [];

if (selected) { //全选

//向selectRowKeys添加选中的值

setSelectedRowKeys([...selectedRowKeys, record.key]);

//更新child数组,将selectParentData中的数据全部过滤添加

setCheckedJob(Array.from(new Set([...checkedJob, ...selectParentData])));

} else { //取消全选

//从父级数组中移除key值

setSelectedRowKeys(

[...selectedRowKeys].filter((d: any) => d !== record.key)

);

//更新child数组,将selectParentData中的数据全部过滤掉

let newArr: any = [];

[...checkedJob].forEach((v) => {

if (selectParentData.indexOf(v) === -1) {

newArr.push(v);

}

});

setCheckedJob(newArr);

}

};

3、二级选中或取消选中逻辑

二级选中或者取消比较简单,只要注意在选中时,如何去考虑是否所有二级全部选中即可。具体代码如下。

//判断b数组中的数据是否全部在a数组中 const isContained = (a: any, b: any) => {

if (!(a instanceof Array) || !(b instanceof Array)) return false;

if (a.length < b.length) return false;

var aStr = a.toString();

for (var i = 0, len = b.length; i < len; i++) {

if (aStr.indexOf(b[i]) == -1) return false;

}

return true;

};

//设置checkbox的onChange事件

const checkChange = (e: any) => {

let praentRowsKey: any;

//找到选中的二级对应的父级key

initialData.current.forEach((v: any) => {

if (v.checkboxData.find((d: any) => d.key === e.target.value)) {

praentRowsKey = v.key;

}

});

if (e.target.checked) {

//选中时 设置当前的check数组

let newCheckedJob = [...checkedJob, e.target.value];

setCheckedJob(newCheckedJob);

//判断当前二级的内容是否全部被选中,如果全部选中,则需要设置selectedRowKeys

//praentRowsKey下的所有子元素

let childArr = initialData.current

.find((d: any) => d.key === praentRowsKey)

?.checkboxData?.map((i: any) => i.key);

// 为当前选择之后的新数组

if (isContained(newCheckedJob, childArr)) {

//全部包含,设置父级

setSelectedRowKeys([...selectedRowKeys, praentRowsKey]);

}

} else {

//取消选中 设置当前的child数组

setCheckedJob(

[...checkedJob].filter((d: number) => d !== e.target.value)

);

//判断当前父级中是否存在praentRowsKey,存在则去除

if (!!~selectedRowKeys.indexOf(praentRowsKey)) {

setSelectedRowKeys(

[...selectedRowKeys].filter((d: any) => d !== praentRowsKey)

);

}

}

};

4、搜索过滤

前3步骤完成后,目前来说,正常的一级二级联动已经完成,现在进行第4步,搜索过滤。

简单的说,搜索的时候,只要改变我们的data,就可以重新渲染Table,这样就可以达成搜索过滤的效果。具体代码如下  

//Search组件搜索时,触发更改data<Search

placeholder="请输入岗位名称"

onSearch={(value) => {

setData(loop(value));

}}

/>

//搜索岗位时,进行过滤

const loop = (searchValue: any) => {

let loopData = initialData.current?.map((item: any) => {    //判断一级是否包含该搜索内容    let parentKey = !!~item.title.indexOf(searchValue);

let childrenData: any = [];

if (item.checkboxData) {

//如果存在二级,则进行二级的循环,过滤出搜索到的value

childrenData = item.checkboxData.filter(

(d: any) => !!~d.title.indexOf(searchValue)

);

} //如果一级有,二级没有,则展示一级下所有的二级    //如果一级没有,二级有,则只展示存在的二级以及对应的一级   //如果一级有,二级有,则展示存在的二级以及对应的一级 //如果一级没有,二级也没有,则不展示

if(parentKey&&!childrenData.length){   return {        title:item.title,        key:item.key,        checkboxData:item.checkboxData      }   }else if((!parentKey || parentKey)&&childrenData.length){      return{        title:item.title,        key:item.key,        checkboxData:childrenData      }    }else{    }

});

  //搜索的值不为空时,返回搜索过滤后都数据(因为map出来的数据中有undefined,所以需要再次进行过滤),为空时返回初始化数据

return searchValue ? loopData.filter((d: any) => d) : initialData.current;

};

5、搜索后,禁止一级全选和取消全选

动态控制table的选择功能,需要使用rowSelection的getCheckboxProps。具体代码如下。

const [selectAllDisabled, setSelectAllDisabled] = useState<boolean>(false); //声明一个变量,控制是否允许选择,默认为false

//在rowSelection中添加getCheckboxProps

const rowSelection = {

selectedRowKeys,

onSelect,

getCheckboxProps: (record: any) => ({

disabled: selectAllDisabled,  //true:禁止,false:允许

}),

};

//在搜索的时候设置

const loop = (searchValue: any) => {

...

setSelectAllDisabled(searchValue ? true : false); //当搜索内容为空时,因为回到的是初始值,所以需要它允许选择,搜索内容不为空时,禁止选择

...

};

6、设置自动展开

前5步完成后,如果不需要设置自动展开,则该功能就可以到此结束。

设置自动展开,需要用到expandable中的onExpand以及expandedRowKeys

expandedRowKeys:展开的行,控制属性

onExpand:点击展开图标时触发,(expanded,record)=> expanded:true:展开,false:收起。record:操作的当前行的数据

具体代码如下:

const [expandedRowKeys, setExpandedRowKeys] = useState<any>([]); //声明变量设置展开的行,默认全都收起

//table的 expandable添加 onExpand,expandedRowKeys

<Table

expandable={{

expandedRowRender,

onExpand,

expandedRowKeys,

}}

/>

//搜索时改变状态

const loop = (searchValue: any) => {

...

//有数据时自动展开所有搜索到的,无数据的时候默认全部收起

setExpandedRowKeys(

searchValue ? initialData.current.map((d: any) => d.key) : []

);

...

};

//控制表格的展开收起

const onExpand = (expanded: any, record: any) => {

if (expanded) {

setExpandedRowKeys([...expandedRowKeys, record.key]); //展开时,将需要展开的key添加到数组中

} else {

setExpandedRowKeys(

[...expandedRowKeys].filter((d: any) => d !== record.key)  //收起时,将该key移除数组

);

}

};

三、优化

一级选择框有三种状态,全选,二级选中某些个,未选中,三种状态对应不同的样式,如下图所示。

这种优化,就需要设置rowSelection的renderCell(注意,rendercell在antd的4.1+版本才能生效),配合Checkbox进行更改。具体代码如下。

1、设置renderCell

将我们在第二步和第五步设置的onSelect以及getCheckboxProps隐藏,再配置renderCell

const rowSelection = {

selectedRowKeys,

// onSelect,

// getCheckboxProps: (record: any) => ({

// disabled: selectAllDisabled,

// }),

renderCell: (checked: any, record: any) => {

//当前record.key对应大初始化数据的一级所有数据

let parentArr = initialData?.current?.find(

(d: any) => d.key === record.key

);

//从所有已经选择过的数据中过滤出在parentArr中的数据

let checkArr = parentArr?.checkboxData?.filter(

(item: any) => checkedJob.indexOf(item.key) > -1

);

return (

<Checkbox

indeterminate={

parentArr?.checkboxData &&

!!checkArr?.length &&

checkArr.length < parentArr.checkboxData.length

? true

: false

} //比较 当过滤后选中数据的长度 < 初始化数据的长度时,设置 indeterminate 状态为true,否则为false

onClick={(e) => onClick(e, record)}

checked={checked}

disabled={selectAllDisabled}

></Checkbox>

);

},

};

2、设置onClick事件

onClick事件其实就是原来的onSelect,具体代码如下

const onClick = (e: any, record: any) => {

//存在搜索时,需要进行处理selectParentData

let initialParent = initialData.current.find(

(d: any) => d.key === record.key

);

let selectParentData = initialParent.checkboxData

? initialParent.checkboxData.map((d: any) => d.key)

: [];

if (e.target.checked) {

//向选中数组中添加key值

setSelectedRowKeys([...selectedRowKeys, record.key]);

//更新child数组,将selectParentData中的数据全部过滤添加

setCheckedJob(Array.from(new Set([...checkedJob, ...selectParentData])));

} else {

//从父级数组中移除key值

setSelectedRowKeys(

[...selectedRowKeys].filter((d: any) => d !== record.key)

);

//更新child数组,将selectParentData中的数据全部过滤掉

let newArr: any = [];

[...checkedJob].forEach((v) => {

if (selectParentData.indexOf(v) === -1) {

newArr.push(v);

}

});

setCheckedJob(newArr);

}

};

四、完整代码

Table+Checkbox模拟Tree完整代码

import React, { useState, useRef, useEffect } from "react";

import { Table, Input, Checkbox } from "antd";

const { Search } = Input;

export default () => {

const initialData: any = useRef([]);

const [data, setData] = useState([

{

key: 1,

title: "普通餐厅(中餐/日料/西餐厅)",

checkboxData: [

{ key: 12, title: "普通服务员" },

{ key: 13, title: "收银" },

{ key: 14, title: "迎宾/接待" },

],

},

{

key: 2,

title: "零售/快消/服装",

checkboxData: [

{ key: 17, title: "基础店员" },

{ key: 19, title: "收银员" },

{ key: 20, title: "理货员" },

],

},

]);

useEffect(() => {

initialData.current = [...data]; //设置初始化值

}, []);

const [checkedJob, setCheckedJob] = useState([12]); //设置选择的二级

const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]); //设置选择的行

const [expandedRowKeys, setExpandedRowKeys] = useState<any>([]); //设置展开的行

const [selectAllDisabled, setSelectAllDisabled] = useState<boolean>(false); //选择的时候,禁止全选

//搜索岗位时,进行过滤

const loop = (searchValue: any) => {

let loopData = initialData.current?.map((item: any) => {

let parentKey = !!~item.title.indexOf(searchValue);

let childrenData: any = [];

if (item.checkboxData) {

//如果存在二级,则进行二级的循环,过滤出搜索到的value

childrenData = item.checkboxData.filter(

(d: any) => !!~d.title.indexOf(searchValue)

);

}

//1.如果一级有,二级没有,则展示一级下所有的二级

//2.如果一级没有,二级有,则只展示存在的二级以及对应的一级

//3.如果一级有,二级有,则展示则存在的二级以及对应的一级

//4.如果一级没有,二级也没有,则不展示

if (parentKey && !childrenData.length) {

return {

title: item.title,

key: item.key,

checkboxData: item.checkboxData,

};

} else if ((!parentKey || parentKey) && childrenData.length) {

return {

title: item.title,

key: item.key,

checkboxData: childrenData,

};

} else {

}

});

setSelectAllDisabled(searchValue ? true : false);

//有数据时自动展开所有搜索到的,无数据的时候默认全部收起

setExpandedRowKeys(

searchValue ? initialData.current.map((d: any) => d.key) : []

);

return searchValue ? loopData.filter((d: any) => d) : initialData.current;

};

const isContained = (a: any, b: any) => {

if (!(a instanceof Array) || !(b instanceof Array)) return false;

if (a.length < b.length) return false;

var aStr = a.toString();

for (var i = 0, len = b.length; i < len; i++) {

if (aStr.indexOf(b[i]) == -1) return false;

}

return true;

};

const checkChange = (e: any) => {

let praentRowsKey: any;

//找到点击child到一级key

initialData.current.forEach((v: any) => {

if (v.checkboxData.find((d: any) => d.key === e.target.value)) {

praentRowsKey = v.key;

}

});

if (e.target.checked) {

//选中时 设置当前的child数组

let newCheckedJob = [...checkedJob, e.target.value];

setCheckedJob(newCheckedJob);

//判断当前child的内容是否全部被选中,如果全部选中,则需要设置selectedRowKeys

//praentRowsKey下的所有子元素

let childArr = initialData.current

.find((d: any) => d.key === praentRowsKey)

?.checkboxData?.map((i: any) => i.key);

// 为当前选择之后的新数组

if (isContained(newCheckedJob, childArr)) {

//全部包含,设置父级

setSelectedRowKeys([...selectedRowKeys, praentRowsKey]);

}

} else {

//取消选中 设置当前的child数组

setCheckedJob(

[...checkedJob].filter((d: number) => d !== e.target.value)

);

//判断当前父级中是否存在praentRowsKey,存在则去除

if (!!~selectedRowKeys.indexOf(praentRowsKey)) {

setSelectedRowKeys(

[...selectedRowKeys].filter((d: any) => d !== praentRowsKey)

);

}

}

};

//父节点变化时,进行的操作

// const onSelect = (record: any, selected: any) => {

// //存在搜索时,需要进行处理selectParentData

// let initialParent = initialData.current.find(

// (d: any) => d.key === record.key

// );

// let selectParentData = initialParent.checkboxData

// ? initialParent.checkboxData.map((d: any) => d.key)

// : [];

// if (selected) {

// //向选中数组中添加key值

// setSelectedRowKeys([...selectedRowKeys, record.key]);

// //更新child数组,将selectParentData中的数据全部过滤添加

// setCheckedJob(Array.from(new Set([...checkedJob, ...selectParentData])));

// } else {

// //从父级数组中移除key值

// setSelectedRowKeys(

// [...selectedRowKeys].filter((d: any) => d !== record.key)

// );

// //更新child数组,将selectParentData中的数据全部过滤掉

// let newArr: any = [];

// [...checkedJob].forEach((v) => {

// if (selectParentData.indexOf(v) === -1) {

// newArr.push(v);

// }

// });

// setCheckedJob(newArr);

// }

// };

//控制表格的展开收起

const onExpand = (expanded: any, record: any) => {

//expanded: true展开,false:关闭

if (expanded) {

setExpandedRowKeys([...expandedRowKeys, record.key]);

} else {

setExpandedRowKeys(

[...expandedRowKeys].filter((d: any) => d !== record.key)

);

}

};

const onClick = (e: any, record: any) => {

//存在搜索时,需要进行处理selectParentData

let initialParent = initialData.current.find(

(d: any) => d.key === record.key

);

let selectParentData = initialParent.checkboxData

? initialParent.checkboxData.map((d: any) => d.key)

: [];

if (e.target.checked) {

//向选中数组中添加key值

setSelectedRowKeys([...selectedRowKeys, record.key]);

//更新child数组,将selectParentData中的数据全部过滤添加

setCheckedJob(Array.from(new Set([...checkedJob, ...selectParentData])));

} else {

//从父级数组中移除key值

setSelectedRowKeys(

[...selectedRowKeys].filter((d: any) => d !== record.key)

);

//更新child数组,将selectParentData中的数据全部过滤掉

let newArr: any = [];

[...checkedJob].forEach((v) => {

if (selectParentData.indexOf(v) === -1) {

newArr.push(v);

}

});

setCheckedJob(newArr);

}

};

const expandedRowRender = (record: any) => {

return (

<div style={{ paddingLeft: 50, boxSizing: "border-box" }}>

<p>请选择岗位,或勾选类别全选岗位</p>

<div>

<Checkbox.Group value={checkedJob}>

{record.checkboxData.map((item: any) => {

return (

<Checkbox

value={item.key}

key={item.key}

onChange={checkChange}

>

{item.title}

</Checkbox>

);

})}

</Checkbox.Group>

</div>

</div>

);

};

const rowSelection = {

selectedRowKeys,

// onSelect,

// getCheckboxProps: (record: any) => ({

// disabled: selectAllDisabled,

// }),

renderCell: (checked: any, record: any) => {

//当前record.key对应大初始化数据的一级所有数据

let parentArr = initialData?.current?.find(

(d: any) => d.key === record.key

);

//从所有已经选择过的数据中过滤出在parentArr中的数据

let checkArr = parentArr?.checkboxData?.filter(

(item: any) => checkedJob.indexOf(item.key) > -1

);

return (

<Checkbox

indeterminate={

parentArr?.checkboxData &&

!!checkArr?.length &&

checkArr.length < parentArr.checkboxData.length

? true

: false

} //比较 当过滤后选中数据的长度 < 初始化数据的长度时,设置 indeterminate 状态为true,否则为false

onClick={(e) => onClick(e, record)}

checked={checked}

disabled={selectAllDisabled}

></Checkbox>

);

},

};

return (

<div

style={{

background: "#fff",

padding: 24,

boxSizing: "border-box",

width: 982,

}}

>

<Search

placeholder="请输入岗位名称"

onSearch={(value) => {

console.log(loop(value));

setData(loop(value));

}}

/>

<Table

showHeader={false}

columns={columns}

expandable={{

expandedRowRender,

onExpand,

expandedRowKeys,

}}

dataSource={data}

pagination={false}

rowSelection={rowSelection}

/>

</div>

);

};

const columns = [{ title: "title", dataIndex: "title", key: "title" }];

以上这篇Ant design vue table 单击行选中 勾选checkbox教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

以上是 Ant design vue table 单击行选中 勾选checkbox教程 的全部内容, 来源链接: utcz.com/p/238262.html

回到顶部