React實現checkbox group多組選項和標籤組顯示的聯動
阿新 • • 發佈:2018-12-19
實現功能:勾選checkbox項,確定後,已勾選的checkbox項以tag標籤的形式展示,tag標籤可快捷刪除。
實現過程:
- 使用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可能會有報錯。。。