React實現(xiàn)checkbox group多組選項和標(biāo)簽組顯示的聯(lián)動

實現(xiàn)功能:勾選checkbox項,確定后萎胰,已勾選的checkbox項以tag標(biāo)簽的形式展示尘吗,tag標(biāo)簽可快捷刪除。

checkbox group

tags

實現(xiàn)過程:

  • 使用React兢孝。
  • 使用Ant Design的Checkbox窿凤、Tag組件。
  • 整個組件主要分為兩個部分:多選框組和Tag標(biāo)簽組跨蟹。

1. 多選框組

class AddInfo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            checkedList: [], // checkbox已選擇的選項
            indeterminate: [], // 全選框-已有選擇非全選
            checkAll: {}, // checkbox group 的全部title狀態(tài)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官網(wǎng)上checkbox group的示例代碼只有一個check group雳殊,本組件是可以有多組的情況,因此主要通過checkedList窗轩,checkAll夯秃,indeterminate,checkTitle幾個狀態(tài)控制checkbox group與單個的checkbox的全勾選品姓、半勾選寝并、無勾選幾種情況的聯(lián)動箫措。
  • checkbox單選的操作是傳入當(dāng)前選擇的所有的選項腹备,然后與原先的可選項對比,計算出checkAll斤蔓,indeterminate植酥,checkTitle的值。每次要先將checkAll,indeterminate友驮,checkTitle置空漂羊,遍歷所有的已選項和待選項。
  • checkbox全選的函數(shù)本來是可以復(fù)用單選的操作卸留,但是全選之后得出checkAll走越,indeterminate,checkTitle的值的過程比單選更簡單一些耻瑟,不用遍歷選項數(shù)組旨指,所以重寫了全選的邏輯,沒有復(fù)用單選的函數(shù)喳整,雖然代碼量多幾行谆构,但是執(zhí)行過程更簡單一些。

2. Tag標(biāo)簽組

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數(shù)組
            checkAll: this.props.checkAll, // 該tag所在的數(shù)組元素是否全部作為tag存在
            indeterminate: this.props.indeterminate, // 該tag所在的數(shù)組元素是否部分作為tag存在
            allCheckArr: this.props.allCheckArr, // 該tag所在的數(shù)組
            checkTitle: this.props.checkTitle // 該tag所在的數(shù)組元素作為tag存在的數(shù)量
        };
    }
    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;

在多選框組對選項勾選之后框都,將選擇結(jié)果傳入Tags標(biāo)簽組件搬素,該組件以Tag標(biāo)簽將已勾選的選項展示出來。Tag標(biāo)簽可以點擊右邊的“x”快捷刪除魏保,刪除后熬尺,多選框組中相應(yīng)的選項也會取消勾選。

3. 組件使用

這兩個組件放在同一個父組件中使用谓罗,實現(xiàn)值傳遞猪杭。

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)}
                 />
          ...
        );
    }
}

代碼經(jīng)過了比較大程度的刪改,刪除了許多無關(guān)功能妥衣,只保留了組件功能的核心部分皂吮,因此僅供參考實現(xiàn)思路。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末税手,一起剝皮案震驚了整個濱河市蜂筹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芦倒,老刑警劉巖艺挪,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異兵扬,居然都是意外死亡麻裳,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門器钟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來津坑,“玉大人,你說我怎么就攤上這事傲霸〗澹” “怎么了眉反?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長穆役。 經(jīng)常有香客問我寸五,道長,這世上最難降的妖魔是什么耿币? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任梳杏,我火速辦了婚禮,結(jié)果婚禮上淹接,老公的妹妹穿的比我還像新娘秘狞。我一直安慰自己,他們只是感情好蹈集,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布烁试。 她就那樣靜靜地躺著,像睡著了一般拢肆。 火紅的嫁衣襯著肌膚如雪减响。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天郭怪,我揣著相機(jī)與錄音支示,去河邊找鬼。 笑死鄙才,一個胖子當(dāng)著我的面吹牛颂鸿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播攒庵,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼嘴纺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了浓冒?” 一聲冷哼從身側(cè)響起栽渴,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎稳懒,沒想到半個月后闲擦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡场梆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年墅冷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片或油。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡寞忿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出装哆,到底是詐尸還是另有隱情罐脊,我是刑警寧澤定嗓,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布蜕琴,位于F島的核電站萍桌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凌简。R本人自食惡果不足惜上炎,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望雏搂。 院中可真熱鬧藕施,春花似錦、人聲如沸凸郑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芙沥。三九已至诲祸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間而昨,已是汗流浹背救氯。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留歌憨,地道東北人着憨。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像务嫡,于是被迫代替她去往敵國和親甲抖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 專業(yè)考題類型管理運(yùn)行工作負(fù)責(zé)人一般作業(yè)考題內(nèi)容選項A選項B選項C選項D選項E選項F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚閱讀 8,984評論 0 13
  • 這個序可能會有些長 先作個自我介紹氛魁,我是一名交互設(shè)計師,90后厅篓。我并不怎么喜歡編輯文章或?qū)扅c什么秀存,就是因為懶,所以...
    IxDKN閱讀 11,059評論 16 160
  • 1羽氮、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,979評論 3 119
  • 進(jìn)入十一月或链,內(nèi)心卻復(fù)蘇了一角。 你看路旁那一垛垛的枯草档押,你能想像一個月前它們的樣子嗎澳盐? 因為上課祈纯,幾乎每天都抄近路...
    單人火鍋閱讀 240評論 0 0
  • 最近瘋狂看意大利紀(jì)錄片,其中一道比西科題吸引了我叼耙。傳統(tǒng)的比西科題是用制作面包的發(fā)酵面團(tuán)來做的腕窥,搭配香辣口味的番茄肉...
    越王的小館閱讀 207評論 0 0