需求:
- 全选复选框 显示情况:点击全选复选框时,所有单个复选框状态变为被勾选状态;并且每一单个复选框边框颜色为蓝色;当点击取消全选复选框被勾选的状态时,所有单个复选框状态恢复初始状态(未被勾选状态)。
- 单个复选框 显示情况:点击某个复选框(单个)时,全选复选框状态为半选状态;将所有单个复选框都点击时,全选复选框状态为被勾选状态。当取消其中一个被勾选状态的复选框(单个),全选复选框状态变为半选状态,当所有单个复选框被勾选状态都被取消时,全选复选框的状态变为初始状态(未被勾选状态)。
在index.tsx中
const PosterList: React.FC = () => {
const [dataList, setDataList] = useState([] as any[]); // 数据
const [checkAll, setCheckAll] = React.useState(false); // 全选复选框
const [indeterminate, setIndeterminate] = React.useState(false); // 半选状态
const [checkedList, setCheckedList] = useState([] as any[]); // 单个复选框
const selectedData = [] // 是否被选中的数据,此数据调用接口获得
// 数据列表接口
const { data } = useRequest(getList, {
defaultParams: [
{
start: 0,
length: 50,
searchMap: {
loginAccount: '',
title: '',
configId: '',
},
},
],
});
// 初始进来如果有选中的值,则为checkedList添加数据
useEffect(() => {
if (selectedData) {
const list = selectedData
.filter((item) => item.type === 4)
.map((item) => {
const id = item.content.id || item.content.configId;
return { ...item.content, id };
});
setCheckedList(list);
}
}, [selectedData]);
// 初始为列表数据添加check
useEffect(() => {
if (data && data.data) {
data.data.forEach((item: { check: boolean }) => {
item.check = false;
});
setDataList(data.data);
}
}, [data]);
// 判断是全选还是半选的逻辑
useEffect(() => {
const checkedListLength = checkedList.length;
// 如果checkedListLength 为0则为选择
if (checkedListLength === 0) {
setCheckAll(false);
setIndeterminate(false);
} else {
setCheckAll(true);
// 判断全选还是半选
setIndeterminate(dataList.some(
(item) => !checkedList.find((items) => items.id === item.id))
);
}
}, [dataList, checkedList.length, checkedList]);
// 单个复选框变化
const onChangeCheck = (e: React.MouseEvent<HTMLElement, MouseEvent>, it: AnyIfEmpty<object>) => {
e.preventDefault();
e.stopPropagation();
// 存储数据当前数据到新数组中
const lists: AnyIfEmpty<object> = [...dataList];
// 将当前的单选框点击变为非
const index = checkedList.findIndex((items) => items.id === it.id);
if (index > -1) {
checkedList.splice(index, 1);
setCheckedList(checkedList);
} else {
setCheckedList([...checkedList, it]);
}
setDataList(lists);
};
// 全选复选框
const onCheckAllChange = (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
// 所有数据保存到 lists中
const lists = [...dataList];
// 定义 flag 判断是否为true
const flag = lists.every((item: { check: boolean }) => item.check === true);
// 遍历lists的 check是否为true
lists.forEach((item: { check: boolean }) => {
item.check = !flag;
});
if (e.target.checked) {
setCheckedList([...lists]);
} else {
setCheckedList([]);
}
setDataList(lists);
};
return (<>
<div className="pagination">
<AllCheckBox
indeterminate={indeterminate}
onChange={onCheckAllChange}
checked={checkAll}
>
所有数据
</AllCheckBox>
</div>
<div className="poster">
{dataList.map((item) => (
<div key={item.id} className="posterListouter">
<Div
className="posterList"
clickId={checkedList.find((items) => items.id === item.id)}
onClick={(e) => onChangeCheck(e, item)}
>
<Checkbox
onClick={(e) => onChangeCheck(e, item)}
checked={checkedList.find((items) => items.id === item.id)}
>
{item.title}
</Checkbox>
<Image preview={false} src={item.placard} alt="" className="image"/>
</Div>
</div>
))}
</div>
</>
);
};
export default PosterList;
在styled.ts中
import styled from 'styled-components';
const Div = styled.div<{
clickId: boolean;
}>`
padding-top: 8px;
&:hover {
border: 1px solid #4287ff;
.ant-checkbox-wrapper .ant-checkbox-inner,
.ant-checkbox .ant-checkbox-inner {
border-color: #1965ff;
}
}
width: 162px;
height: 296px;
/* margin-right: 16px; */
margin-bottom: 16px;
padding-left: 12px;
background: #ffffff;
border: ${(props: { clickId: boolean }) =>
props.clickId ? '1px solid #1965FF' : '1px solid #ffffff'};
border-radius: 2px;
.title {
display: inline-block;
width: 112px;
height: 22px;
margin-left: 8px;
overflow: hidden;
color: #262626;
font-weight: 400;
font-size: 14px;
line-height: 30px;
white-space: nowrap;
text-overflow: ellipsis;
}
.image {
width: 138px;
height: 244px;
margin-top: 1px;
/* margin: 1px 12px 12px; */
}
`;
const AllCheckBox = styled(Checkbox)`
margin-right: 4px;
margin-bottom: 0;
`;
export { Div, AllCheckBox };
总结
- e.stopPropagation() 阻止事件冒泡,e.preventDefault() 阻止事件默认行为。
- filter() 过滤出一些符合条件的元素,返回一个新数组,不改变原数组。
- map() 数组的遍历,用来接收一个返回值,创建一个新数组,不改变原数组。
- forEach() 数组遍历,且只能够遍历数组,不接受返回值或返回值为 undefined。
- some() 检测数组中是否含有某一个值,返回一个布尔值,如果数组中有任意一个元素满足给定的条件,结果就为 true,否则为false。
- find() 查找数组中符合条件的元素,若有多个符合条件的元素,则返回第一个元素。
- findIndex() 查找数组中符合条件的元素索引,若有多个符合条件的元素,则返回第一个元素索引。
- splice() 没有参数,返回空数组,原数组不变。一个参数,从该参数表示的索引位开始截取,直至数组结束,返回截取的数组,原数组改变。两个参数,第一个参数表示开始截取的索引位,第二个参数表示截取的长度,返回截取的 数组,原数组改变;三个或者更多参数,第三个及以后的参数表示要从截取位插入的值。
- every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供),满足条件返回true,否则返回false。