zoukankan      html  css  js  c++  java
  • React实现checkbox group多组选项和标签组显示的联动

    实现功能:勾选checkbox项,确定后,已勾选的checkbox项以tag标签的形式展示,tag标签可快捷删除。

    checkbox group
    tags

    实现过程:

    • 使用React。
    • 使用Ant Design的Checkbox、Tag组件。
    • 整个组件主要分为两个部分:多选框组和Tag标签组。

    1. 多选框组

    class AddInfo extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                checkedList: [], // checkbox已选择的选项
                indeterminate: [], // 全选框-已有选择非全选
                checkAll: {}, // checkbox group 的全部title状态true/false
                tempList: [], // 临时存储checkbox已选择的选项
                checkTitle: {} // checkbox group中已选择的title(全选)
            };
        }
    
        /* 确定勾选 */
        handleOk = () => {
            if (this.state.tempList.length > 0) {
                // 将已选择信息传给Tags组件
                this.props.getChecked({
                    checkedItem: this.state.tempList,
                    checkAll: this.state.checkAll,
                    indeterminate: this.state.indeterminate,
                    checkTitle: this.state.checkTitle
                });
            }
        }
    
        /* checkbox单选 */
        onChange = (allCheckArr, checkedList) => {
            let checkAll = this.state.checkAll;
            let indeterminate = [];
            let checkTitle = {};
            Object.keys(allCheckArr).forEach((title) => {
                checkTitle[title] = 0;
                for (let checkedItem of checkedList || []) {
                    if (allCheckArr[title].includes(checkedItem)) {
                        checkTitle[title]++;
                        checkAll[title] = checkTitle[title] === allCheckArr[title].length;
                        indeterminate[title] = !!checkTitle[title] && (checkTitle[title] < allCheckArr[title].length);
                    }
                }
                if (checkTitle[title] === 0) { // 选项组下仅有一个选项时取消选中
                    checkAll[title] = false;
                }
            });
            this.setState({
                checkedList,
                tempList:checkedList,
                indeterminate: indeterminate,
                checkAll: checkAll,
                checkTitle: checkTitle
            });
        }
    
        /* checkbox全选 */
        onCheckAllChange = (allCheckArr, title, e) => {
            this.state.checkAll[title] = e.target.checked;
            let checkedListT = [];
            checkedListT.push(...this.state.checkedList);
            let indeterminate = this.state.indeterminate || [];
            let checkTitle = this.state.checkTitle || {};
            if (e.target.checked === true) { // 全选
                checkedListT.push(...allCheckArr[title]);
                checkedListT = Array.from(new Set(checkedListT)); // 去重(原先indeterminate为true的情况)
                checkTitle[title] = allCheckArr[title].length;
            } else { // 取消全选
                let common = checkedListT.filter(v => allCheckArr[title].includes(v));
                checkedListT = checkedListT.concat(common).filter(v => checkedListT.includes(v) && !common.includes(v));
                checkTitle[title] = 0;
            }
            indeterminate[title] = false;
            this.setState({
                tempList: checkedListT,
                checkedList: checkedListT,
                indeterminate: indeterminate,
                checkTitle: checkTitle
            });
        }
    
        render() {
            const { checkedList, checkAll, indeterminate } = this.state;
            const { allCheckArr } = this.props;
            return (
                <div className={styles.modalcontent} >
                    {
                        allCheckArr.map( ({ title, value }, key ) => (
                            <div className={styles.checksgroup}>
                                <div>
                                    <Checkbox
                                    indeterminate={indeterminate[title]}
                                    onChange={this.onCheckAllChange.bind(this, allCheckArr, title)}
                                    checked={checkAll[title]}
                                    >
                                        {title}
                                    </Checkbox>
                                </div>
                                <br />
                                <CheckboxGroup className={styles.contents} options={value} value={checkedList} onChange={this.onChange.bind(this, allCheckArr)} />
                            </div>
                    ))}
                </div>
            );
        }
    }
    
    export default AddInfo;
    
    
    • 由于Ant Design官网上checkbox group的示例代码只有一个check group,本组件是可以有多组的情况,因此主要通过checkedList,checkAll,indeterminate,checkTitle几个状态控制checkbox group与单个的checkbox的全勾选、半勾选、无勾选几种情况的联动。
    • checkbox单选的操作是传入当前选择的所有的选项,然后与原先的可选项对比,计算出checkAll,indeterminate,checkTitle的值。每次要先将checkAll,indeterminate,checkTitle置空,遍历所有的已选项和待选项。
    • checkbox全选的函数本来是可以复用单选的操作,但是全选之后得出checkAll,indeterminate,checkTitle的值的过程比单选更简单一些,不用遍历选项数组,所以重写了全选的逻辑,没有复用单选的函数,虽然代码量多几行,但是执行过程更简单一些。

    2. Tag标签组

    import React from 'react';
    import { Tag } from 'antd';
    import styles from './index.less';
    
    class Tags extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                items: this.props.items, // 需要显示的tag数组
                checkAll: this.props.checkAll, // 该tag所在的数组元素是否全部作为tag存在
                indeterminate: this.props.indeterminate, // 该tag所在的数组元素是否部分作为tag存在
                allCheckArr: this.props.allCheckArr, // 该tag所在的数组
                checkTitle: this.props.checkTitle // 该tag所在的数组元素作为tag存在的数量
            };
        }
        componentWillReceiveProps = ( value, nextState) => {
            this.setState({
                items: value.items,
                checkAll: value.checkAll,
                indeterminate: value.indeterminate,
                allCheckArr: value.allCheckArr,
                checkTitle: value.checkTitle
            });
        }
    
        delete = (key, value, e) => {
            e.preventDefault();
            let items = this.state.items;
            let checkAll = this.state.checkAll;
            let indeterminate = this.state.indeterminate;
            let allCheckArr = this.state.allCheckArr;
            let checkTitle = this.state.checkTitle;
            items.splice(key, 1);
            for (let title in allCheckArr) {
                for (let item of allCheckArr[title]) {
                    if (item === value) {
                        checkTitle[title]--;
                        checkAll[title] = false;
                        if (checkTitle[title] === 0) { // 该选项组下的选项全部删除
                            indeterminate[title] = false;
                        } else {
                            indeterminate[title] = true;
                        }
                    }
                }
            }
            this.setState({
                items: items,
                checkAll: checkAll,
                indeterminate: indeterminate,
                checkTitle: checkTitle
            });
            this.props.changeCheckeditems(items);
        }
        render() {
            const items = this.state.items?this.state.items:[];
            return (
                <div>
                    {
                        items.map((value, key) => (
                            <Tag className={styles.singletag} closable key={key} onClose={this.delete.bind(this, key, value)}>{value}</Tag>
                        ))}
                </div>
            );
        }
    }
    
    export default Tags;
    

    在多选框组对选项勾选之后,将选择结果传入Tags标签组件,该组件以Tag标签将已勾选的选项展示出来。Tag标签可以点击右边的“x”快捷删除,删除后,多选框组中相应的选项也会取消勾选。

    3. 组件使用

    这两个组件放在同一个父组件中使用,实现值传递。

    class parent extends React.Component {
        /* 获取待选择选项 */
        getAllCheckArr = () => {
           ...
                        this.setState({
                            allCheckArr 
                            ...
                        });
             ...
        }
     
        /* 获取checkbox选择的选项 */
        getChecked = (val) => {
            this.setState({
                checkedItem: val.checkedItem,
                checkAll: val.checkAll,
                indeterminate: val.indeterminate,
                checkTitle: val.checkTitle
            });
        }
      
        /* 获取tags删除后的选项 */
        changeChecked = (val) => {
            ...
            this.setState({
                changedItem: val
            });
            ...
        }
        render() {
            const { checkedItem, changedItem,, checkAll, indeterminate, checkTitle } = this.state;
            return (
                ...
                    <AddInfo
                           checkList={this.state.checkedItem}
                           allCheckArr={this.state.allCheckArr|| []}
                           getChecked={this.getChecked.bind(this)}
                     />
                     <Tags
                           allCheckArr={this.state.allCheckArr|| []}
                           checkAll={checkAll}
                           checkTitle={checkTitle}
                           indeterminate={indeterminate}
                           items={checkedItem}
                           changeChecked={this.changeChecked.bind(this)}
                     />
              ...
            );
        }
    }
    

    代码经过了比较大程度的删改,删除了许多无关功能,只保留了组件功能的核心部分,因此直接copy可能会有报错。。。

  • 相关阅读:
    RocketMQ——角色与术语详解
    大数据学习方向
    连接mysql数据库报错java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone.
    exception is feign.RetryableException: Connection refused (Connection refused) executing GET http://......
    【BZOJ3261】最大异或和(可持久化Trie)
    【BZOJ4552】排序(线段树,二分)
    【CodeChef】LECOINS(同余最短路,背包DP)
    【BZOJ2118】墨墨的等式(同余最短路)
    【BZOJ5249】IIIDX(贪心,线段树)
    【gym102394L】LRU Algorithm(自然溢出哈希)
  • 原文地址:https://www.cnblogs.com/chaoxiZ/p/9897285.html
Copyright © 2011-2022 走看看