背景
antd Table组件在升级到3.19.1版本后,通过选中checkbox来选中整行时,checkbox不能被选中,并报错“can’t read property shiftKey of undefined”
那就自己写一个吧。
还是要用antD的checkbox组件,毕竟样式还挺好看的。
DOM样式
import {Checkbox, Icon} from 'antd'; // 借用antD checkbox样式
<ul className={styles.multiBodyWrap}>
{
dataList && dataList.length > 0 && dataList.map((item) => {
const {id, attend_date, subject, attend_status_list, student_name, attend_time} = item;
return (
<li key={id} className={styles.multiBodyItem} onClick={this.rowChose.bind(this,id,attend_status_list)}> // 事件冒泡,选中整行
<Checkbox checked={selectedIdArr.indexOf(id) !== -1}></Checkbox>
<span className={`${isZouban ? styles.multiSubjectBDate : styles.multiBDate}`}>{attend_date}</span>
<span className={`${isZouban ? styles.multiSubjectBStatus : styles.multiBStatus}`}>{statesToNameObj[attend_status_list]}</span>
<span className={styles.multiBName}>{student_name}</span>
<span className={styles.multiBTime}>{attend_time}</span>
</li>
);
})
}
</ul>
{/* 底部操作fixed框 */}
<div className={`${styles.footWrap} ${isMultiEdit && dataList && dataList.length!==0 ? '' : styles.hide}`}>
<Checkbox onChange={this.selectAllMock.bind(this)} checked={selectedIdArr.length===allIdArr.length}>
<span className={styles.txt}>全选</span>
</Checkbox>
<span className={styles.edit}>
{
selectedIdArr && selectedIdArr.length > 0 ? editTxtActive : (<span className={styles.txtNormal}>修改状态</span>)
}
</span>
</div>
js部分
逐条选中
-
样式上:
利用selectedIdArr.indexOf(id) !== -1判断当前item的id是否在已选id数组selectedIdArr中,true时表示在该条目被选中,Checkbox为选中态。
<Checkbox checked={selectedIdArr.indexOf(id) !== -1}>控制选中/取消样式
-
功能上:
主要介绍全选方法rowChose
// selectedIdArr:[], 选中的id都存放在此数组中
// allIdArr:[], 当前页面展示的所有数据的id组成的数组
此处为axios请求得到数据后,收集所有id
// 将数据中所有的id存在allIdArr数组中,全选用
let dataAllIds = [];
dataList && dataList.length > 0 && dataList.map((item) => {
dataAllIds.push(item.id);
});
this.setState({
allIdArr: dataAllIds,
});
利用事件冒泡,选中整行的点击事件
rowChose = (rowId,attend_status_list) => {
let arr = JSON.parse(JSON.stringify(this.state.selectedIdArr)); // 深拷贝一个数组,防止对原数组进行不可预知干扰
let location = arr.indexOf(rowId);
if(location !== -1) { // 已经存在,说明现在是取消全选操作
arr.splice(location,1);
this.setState({
hasSelectAll:false, // 此处一定要记得将全选标识置为false
});
} else {
arr.push(rowId)
}
this.setState({
selectedIdArr: arr,
selectedAttendType: attend_status_list,
}, () => {
let {allIdArr, selectedIdArr} = this.state;
if(allIdArr.length === selectedIdArr.length) { // 请求得到dataList时,将
this.setState({
hasSelectAll: true
})
}
})
}
注:
rowChose如果是取消当前选中行,要记得将将全选标识置为false。我在此处出过bug。bug复现路径是:
全选按钮-点击某行进行取消-全选按钮-结果全被取消了,而不是预期的全部选中。
一键全选功能
-
样式上:
判断selectedIdArr和allIdArr数组长度是否相等。
-
功能上:
全选:将allIdArr的值都赋给selectedIdArr; 取消全选:清空selectedIdArr数组。
// 底部fixed区的全选按钮功能
selectAllMock = () => {
let {allIdArr} = this.state;
this.setState({
hasSelectAll: !this.state.hasSelectAll
}, () => {
let {hasSelectAll} = this.state;
if(hasSelectAll){
this.setState({
selectedIdArr:allIdArr,
});
} else {
this.setState({
selectedIdArr:[],
})
}
})
}
言简意赅
selectedIdArr:存在已选择item的id
allIdArr:所有数据的id组成的id全集
通过操作selectedIdArr数组中的元素增减来实现选中/取消
更新更新
在后期的自测中发现了一个很偶现的checkbox点击闪一下的问题。花了挺长时间解决,记录一下。
原因分析:
antD的checkbox本身具有点击事件,而我在它的父级li中又写了点击事件rowChose,所以:checkbox的点击事件冒泡到li的rowChose,和li本身的rowChose事件在短时间内快速触发,checkbox就呈现出了先选中又被取消的过程,表现出来就是闪了一下。
写到这里也才发现自己之前引用的antD checkbox写法是有问题的,应该将复选框后面要显示的部分全部放在(此处展示要显示的其他布局),然后利用Checkbox的onChange事件进行判断即可。
因为是我项目测试末期才发现的这个问题,再重写样式成本比较高,就只能“将错就错”,利用原生进行修补。遂做出如下修改:
1.给rowChose方法传参
2.利用节流原理