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