组件名:checkbox-select
组件截图:
文件内容:
src/pages/checkbox-select/index.js
import CheckboxSelect from 'components/checkbox-select';
function Page() {
// 演示数据
const testList = [
{ label: '#演示项目 1', value: 1 },
{ label: '#演示项目 2', value: 2 },
{ label: '#演示项目 3', value: 3 },
{ label: '#演示项目 4', value: 4 },
{ label: '#演示项目 5', value: 5 },
{ label: '#演示项目 6', value: 6 },
{ label: '#演示项目 7', value: 7 },
{ label: '#演示项目 8', value: 8 },
];
// 选择返回数据
const changeCallback = (data) => {
console.log('callback data---->', data);
};
return (
<>
<CheckboxSelect optionsList={testList} changeCallback={changeCallback} />
</>
);
}
export default Page;
View Code
src/components/checkbox-select/index.js
/**
* 包含多选框的下拉列表,含全选和全不选操作
* */
import { useEffect, useState, useCallback, useRef } from 'react';
import PropTypes from 'prop-types';
import { Checkbox, Button } from 'antd';
import 'less/components/checkbox-select/index.less';
function CheckboxSelect(props) {
const { optionsList, changeCallback } = props;
const cancelBtn = useRef();
const [showText, setShowText] = useState('全部');
const [isActive, setIsActive] = useState(false);
const [checkAll, setCheckAll] = useState(true);
const [indeterminate, setIndeterminate] = useState(false);
const [checkboxValList, setCheckboxValList] = useState([]);
const [checkboxOldValList, setCheckboxOldValList] = useState([]);
// 多选框列表被触发的时候
const checkboxChange = (list) => {
setCheckboxValList(list);
setIndeterminate(!!list.length && list.length < optionsList.length);
};
// 确定操作
const confirm = () => {
setCheckboxOldValList(checkboxValList);
setIsActive(false);
// 返回最终数据
changeCallback(checkboxValList);
// 把选择的文本显示在框框内
if (checkboxValList.length === optionsList.length) {
setShowText('全部');
return;
}
const textArr = [];
optionsList.forEach((item1) => {
checkboxValList.forEach((item2) => {
if (item1.value === item2) {
textArr.push(item1.label);
}
});
});
setShowText(textArr.join(','));
};
// 取消操作
const cancel = () => {
setCheckboxValList(checkboxOldValList);
setIsActive(false);
};
// 点击操作
const toggleClick = (ev) => {
// 阻止事件冒泡
ev.nativeEvent.stopImmediatePropagation();
const status = !isActive;
setIsActive(status);
};
// 全选/全不选 操作
const onCheckAllChange = () => {
const status = !checkAll;
setCheckAll(status);
// 判断是全选还是全不选
const listArr = [];
if (status) {
optionsList.forEach((item) => {
listArr.push(item.value);
});
}
setCheckboxValList(listArr);
setIndeterminate(false);
};
// 触发内容区域
const documentEvent = () => {
cancelBtn.current.click();
};
// 监听全选/全不选状态
useEffect(() => {
setCheckAll(optionsList.length === checkboxValList.length);
setIndeterminate(!!checkboxValList.length && checkboxValList.length < optionsList.length);
}, [checkboxValList]);
// 组件卸载
const unComponent = () => {
// console.log('组件卸载');
document.removeEventListener('click', documentEvent);
};
// 初始操作
const init = useCallback(() => {
// 设置checkbox默认全选
const listArr = [];
optionsList.forEach((item) => {
listArr.push(item.value);
});
setCheckboxValList(listArr);
setCheckboxOldValList(listArr);
// 空白文档处被点击
document.addEventListener('click', documentEvent);
}, []);
useEffect(() => {
init();
return unComponent;
}, []);
return (
<>
<div className={`checkbox-select ${isActive ? 'checkbox-select-active' : ''}`}>
<div className="cs__input-wrap" onClick={toggleClick}>
<div className="cs__input-text">{showText}</div>
<span className="cs__input-icon"></span>
</div>
<div
className="cs__tool"
onClick={(ev) => {
ev.nativeEvent.stopImmediatePropagation();
}}
>
<Checkbox.Group onChange={checkboxChange} value={checkboxValList}>
<ul className="cs__checkbox-list">
{optionsList.length ? (
optionsList.map((item) => {
return (
<li key={item.value}>
<Checkbox value={item.value}>{item.label}</Checkbox>
</li>
);
})
) : (
<li className="empty">暂无数据</li>
)}
</ul>
</Checkbox.Group>
<div className="cs__button" style={{ display: optionsList.length ? '' : 'none' }}>
<Checkbox indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll}>
全选/全不选
</Checkbox>
<Button type="primary" size="small" onClick={confirm}>
确定
</Button>
<Button size="small" onClick={cancel} ref={cancelBtn}>
取消
</Button>
</div>
</div>
</div>
</>
);
}
CheckboxSelect.propTypes = {
//下拉列表数据
optionsList: PropTypes.array,
// 确定按钮触发返回函数:return array
changeCallback: PropTypes.func,
};
CheckboxSelect.defaultProps = {
optionsList: [],
};
export default CheckboxSelect;
View Code
src/less/components/checkbox-select/index.less
* {
padding: 0;
margin: 0;
list-style: none;
}
// --------------------------------------- 组件样式开始 ---------------------------------
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.checkbox-select {
margin: 0px auto;
top: 100px;
max-width: 260px;
position: relative;
.cs__input-wrap {
position: relative;
cursor: pointer;
.cs__input-text {
width: 100%;
padding: 0 30px 0 10px;
height: 34px;
line-height: 34px;
border: 1px solid #ddd;
user-select: none;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.cs__input-icon {
position: absolute;
display: block;
right: 1px;
top: 1px;
height: 32px;
width: 30px;
&::after {
content: ' ';
display: block;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 8px solid #555;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
}
.cs__tool {
display: none;
position: absolute;
width: 100%;
left: 0;
top: 34px;
background-color: #fff;
border: 1px solid #f1f1ff;
animation: fadeIn 0.5s 0s;
.cs__checkbox-list {
margin-bottom: 0;
max-height: 200px;
overflow: hidden auto;
label {
padding: 5px 10px;
&:hover {
background-color: #f1f1f1;
}
}
.ant-checkbox-wrapper {
width: 100%;
}
.empty {
text-align: center;
min-height: 100px;
line-height: 100px;
font-size: 12px;
color: #999;
}
}
.ant-checkbox-group {
padding-top: 5px;
width: 100%;
}
.cs__button {
width: 100%;
border-top: 1px solid #f1f1f1;
padding: 5px 10px;
display: inline-block;
label {
font-size: 12px;
user-select: none;
color: #555;
}
button {
margin: 0 5px;
float: right;
}
.ant-btn-primary {
margin-right: 0;
}
}
}
}
.checkbox-select-active {
.cs__tool {
display: block;
}
}
View Code