React 下拉多选,全选/全不选功能组件

组件名: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
原文地址:https://www.cnblogs.com/zion0707/p/13962615.html