惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
InfoQ
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
P
Privacy & Cybersecurity Law Blog
Cloudbric
Cloudbric
云风的 BLOG
云风的 BLOG
S
Secure Thoughts
Stack Overflow Blog
Stack Overflow Blog
G
Google Developers Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
S
SegmentFault 最新的问题
博客园 - Franky
T
Tenable Blog
T
The Blog of Author Tim Ferriss
博客园 - 三生石上(FineUI控件)
V
V2EX
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Troy Hunt's Blog
罗磊的独立博客
WordPress大学
WordPress大学
SecWiki News
SecWiki News
The Cloudflare Blog
S
Securelist
小众软件
小众软件
Schneier on Security
Schneier on Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 叶小钗
Google Online Security Blog
Google Online Security Blog
Forbes - Security
Forbes - Security
阮一峰的网络日志
阮一峰的网络日志
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
W
WeLiveSecurity
A
Arctic Wolf
大猫的无限游戏
大猫的无限游戏
The Last Watchdog
The Last Watchdog
C
Cybersecurity and Infrastructure Security Agency CISA
宝玉的分享
宝玉的分享
MyScale Blog
MyScale Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
博客园 - 司徒正美
Vercel News
Vercel News
H
Help Net Security
Y
Y Combinator Blog
PCI Perspectives
PCI Perspectives
L
LINUX DO - 最新话题
H
Hackread – Cybersecurity News, Data Breaches, AI and More

博客园 - Zion0707

Codex接入DeepSeek token实现对话与操作,so easy! Openclaw只能聊天不能操作解决方案 Ubuntu从零搭建Openclaw Openclaw安装问题记录 React数字滚动,增加或减少效果 react hooks实现对元素拖拽及鼠标滚轮缩放 前端实现图片文字识别并提取 ECharts实现两条曲线数据比较,数据高出区域高亮显示 canvas实现视频播放并支持自动播放 fabricjs实现虚线流动动画效果 React国际化方案及示例 fabricjs如何导入echarts fabricjs元素对齐方式实现 萤石云视频监控和回放方案 React仿photoshop参考线功能 react-router-dom v6 使用 “DatePicker”不能用作 JSX 组件。 Element plus的tree组件实现单选和搜索功能 16进制相关操作方法 js 版 AES-128 算法加解密 js 版
React 下拉多选,全选/全不选功能组件
Zion0707 · 2020-11-12 · via 博客园 - Zion0707

组件名: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