tree添加一级项

This commit is contained in:
catchonme 2019-09-10 15:32:54 +08:00
parent 1689e32097
commit b64188f9dd
3 changed files with 117 additions and 83 deletions

View File

@ -1,3 +1,29 @@
@mixin tree-input {
> i {
display: inline-block;
cursor: pointer;
margin-left: px2rem(5px);
}
> input {
margin-left: px2rem(15px);
padding: px2rem(5px);
width: px2rem(150px);
height: px2rem(25px);
color: $Form-input-color;
&::placeholder {
color: $Form-input-placeholderColor;
user-select: none;
}
&:focus {
outline: none;
border: $borderWidth solid $info;
}
}
}
// todo // todo
.#{$ns}TreeControl { .#{$ns}TreeControl {
border: 1px solid $Form-input-borderColor; border: 1px solid $Form-input-borderColor;
@ -31,30 +57,7 @@
} }
> li { > li {
> i { @include tree-input;
display: inline-block;
cursor: pointer;
margin-left: 5px;
}
> input {
margin-left: 15px;
padding: px2rem(5px);
width: px2rem(150px);
height: px2rem(25px);
color: $Form-input-color;
//height: $Form-input-lineHeight * $Form-input-fontSize;
&::placeholder {
color: $Form-input-placeholderColor;
user-select: none;
}
&:focus {
outline: none;
border: $borderWidth solid $info;
}
}
} }
} }
@ -72,7 +75,7 @@
> span > i { > span > i {
display: inline-block; display: inline-block;
cursor: pointer; cursor: pointer;
margin-left: 5px; margin-left: px2rem(5px);
} }
} }
@ -82,35 +85,28 @@
&--isEdit { &--isEdit {
display: inline-block; display: inline-block;
> i { @include tree-input;
display: inline-block;
cursor: pointer;
margin-left: 5px;
}
> input {
margin-left: 15px;
padding: px2rem(5px);
width: px2rem(150px);
height: px2rem(25px);
color: $Form-input-color;
//height: $Form-input-lineHeight * $Form-input-fontSize;
&::placeholder {
color: $Form-input-placeholderColor;
user-select: none;
}
&:focus {
outline: none;
border: $borderWidth solid $info;
}
}
} }
} }
&-rootItem > a > i { &-rootItem {
margin-left: 0 !important; > a > i {
margin-left: 0 !important;
}
.#{$ns}Tree-addTop {
height: px2rem(25px);
line-height: px2rem(25px);
cursor: pointer;
padding-left: $Tree-indent;
> p > span {
padding-left: px2rem(5px);
}
&-input {
@include tree-input
}
}
} }
&-itemArrow { &-itemArrow {

View File

@ -9,7 +9,6 @@ import {eachTree, isVisible, isObject} from '../utils/helper';
import {Option, Options, value2array} from './Checkboxes'; import {Option, Options, value2array} from './Checkboxes';
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable} from '../theme';
import {highlight} from '../renderers/Form/Options'; import {highlight} from '../renderers/Form/Options';
import debounce = require('lodash/debounce');
interface TreeSelectorProps { interface TreeSelectorProps {
classPrefix: string; classPrefix: string;
@ -72,6 +71,7 @@ interface TreeSelectorState {
addItem: Option | null; addItem: Option | null;
addingItem: Option | null; addingItem: Option | null;
editingItem: Option | null; editingItem: Option | null;
addTop: boolean;
} }
export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelectorState> { export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelectorState> {
@ -135,7 +135,8 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
editItem: null, // 点击编辑时的 item editItem: null, // 点击编辑时的 item
addItem: null, // 点击添加时的 item addItem: null, // 点击添加时的 item
addingItem: null, // 添加后的 item addingItem: null, // 添加后的 item
editingItem: null // 编辑后的 item editingItem: null, // 编辑后的 item
addTop: false // 添加一级
}); });
} }
@ -330,25 +331,34 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
}); });
} }
addItem(item: Option, isFolder: boolean) { addItem(item: Option | null, isFolder: boolean) {
const {addMode, openAddDialog, valueField} = this.props; const {addMode, openAddDialog, valueField} = this.props;
let {hoverItem, unfolded} = this.state; let {hoverItem, unfolded} = this.state;
if (addMode === 'dialog') { if (addMode === 'dialog') {
openAddDialog && openAddDialog(hoverItem) openAddDialog && openAddDialog(item ? hoverItem : null)
} else if (addMode === 'normal') { } else if (addMode === 'normal') {
// 添加时,默认折叠的文件夹需要展开 // item 为 null 时为添加一级
if (isFolder && !unfolded[item[valueField as string]]) { if (item) {
unfolded = { // 添加时,默认折叠的文件夹需要展开
...unfolded, if (isFolder && !unfolded[item[valueField as string]]) {
[item[valueField as string]]: !unfolded[item[valueField as string]], unfolded = {
...unfolded,
[item[valueField as string]]: !unfolded[item[valueField as string]],
}
} }
}
this.setState({ this.setState({
addItem: item, addItem: item,
editItem: null, editItem: null,
unfolded unfolded
}); });
} else {
this.setState({
addTop: true,
editItem: null,
addItem: null
});
}
} }
} }
@ -387,13 +397,15 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
this.setState({ this.setState({
addingItem: null, addingItem: null,
addItem: null addItem: null,
addTop: false
}) })
} }
cancelAddItem() { cancelAddItem() {
this.setState({ this.setState({
addItem: null addItem: null,
addTop: false
}); });
} }
@ -461,6 +473,14 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
editMode, editMode,
deletable deletable
} = this.props; } = this.props;
const {
addItem,
editItem,
hoverItem,
unfolded,
addTop,
value: stateValue
} = this.state;
let childrenChecked = 0; let childrenChecked = 0;
let ret = list.map((item, key) => { let ret = list.map((item, key) => {
@ -497,8 +517,8 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
if ( if (
!nodeDisabled && !nodeDisabled &&
((maxLength && !selfChecked && this.state.value.length >= maxLength) || ((maxLength && !selfChecked && stateValue.length >= maxLength) ||
(minLength && selfChecked && this.state.value.length <= minLength)) (minLength && selfChecked && stateValue.length <= minLength))
) { ) {
nodeDisabled = true; nodeDisabled = true;
} }
@ -543,13 +563,13 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
!nodeDisabled && this.handleLeave() !nodeDisabled && this.handleLeave()
} }
> >
{!this.state.editItem || isObject(this.state.editItem) && (this.state.editItem as Option)[valueField] !== item[valueField] ? ( {!editItem || isObject(editItem) && (editItem as Option)[valueField] !== item[valueField] ? (
<a> <a>
{!isLeaf ? ( {!isLeaf ? (
<i <i
onClick={() => this.toggleUnfolded(item)} onClick={() => this.toggleUnfolded(item)}
className={cx('Tree-itemArrow', { className={cx('Tree-itemArrow', {
'is-folded': !this.state.unfolded[item[valueField]], 'is-folded': !unfolded[item[valueField]],
})} })}
/> />
) : null} ) : null}
@ -579,10 +599,11 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
{highlightTxt ? highlight(item[nameField], highlightTxt) : item[nameField]} {highlightTxt ? highlight(item[nameField], highlightTxt) : item[nameField]}
</span> </span>
{/* 非添加时 && 非编辑时 && 鼠标覆盖时是当前item时显示添加/编辑/删除图标 */} {/* 非添加时 && 非编辑时 && 鼠标覆盖时是当前item时显示添加/编辑/删除图标 */}
{!this.state.addItem {!addTop
&& !this.state.editItem && !addItem
&& isObject(this.state.hoverItem) && !editItem
&& (this.state.hoverItem as Option)[valueField as string] === item[valueField] ? ( && isObject(hoverItem)
&& (hoverItem as Option)[valueField as string] === item[valueField] ? (
<span> <span>
{addMode ? <i className="fa fa-plus" onClick={() => this.addItem(item, !isLeaf)}></i> : null} {addMode ? <i className="fa fa-plus" onClick={() => this.addItem(item, !isLeaf)}></i> : null}
{deletable ? <i className="fa fa-minus" onClick={() => this.deleteItem(item)}></i> : null} {deletable ? <i className="fa fa-minus" onClick={() => this.deleteItem(item)}></i> : null}
@ -592,19 +613,19 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
</a> </a>
) : ( ) : (
<div className={cx('Tree-item--isEdit')}> <div className={cx('Tree-item--isEdit')}>
<input placeholder='label' defaultValue={item['label']} onChange={(e) => this.onChangeEditItem(item, e.currentTarget.value)}/> <input defaultValue={item['label']} onChange={(e) => this.onChangeEditItem(item, e.currentTarget.value)}/>
<i className="fa fa-check" onClick={this.confirmEditItem}></i> <i className="fa fa-check" onClick={this.confirmEditItem}></i>
<i className="fa fa-close" onClick={this.cancelEditItem}></i> <i className="fa fa-close" onClick={this.cancelEditItem}></i>
</div> </div>
)} )}
{/* 有children而且为展开状态 或者 添加child时 */} {/* 有children而且为展开状态 或者 添加child时 */}
{((childrenItems && this.state.unfolded[item[valueField]]) || this.state.addItem && (this.state.addItem[valueField] === item[valueField])) ? ( {((childrenItems && unfolded[item[valueField]]) || addItem && (addItem[valueField] === item[valueField])) ? (
<ul <ul
className={cx('Tree-sublist')} className={cx('Tree-sublist')}
> >
{this.state.addItem && this.state.addItem[valueField] === item[valueField] ? ( {addItem && addItem[valueField] === item[valueField] ? (
<li> <li>
<input placeholder='label' onChange={(e) => this.onChangeAddItem(e.currentTarget.value)}/> <input onChange={(e) => this.onChangeAddItem(e.currentTarget.value)}/>
<i className="fa fa-check" onClick={this.confirmAddItem}></i> <i className="fa fa-check" onClick={this.confirmAddItem}></i>
<i className="fa fa-close" onClick={this.cancelAddItem}></i> <i className="fa fa-close" onClick={this.cancelAddItem}></i>
</li> </li>
@ -623,10 +644,10 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
} }
render() { render() {
const {className, placeholder, hideRoot, rootLabel, showIcon, classnames: cx} = this.props; const {className, placeholder, hideRoot, rootLabel, showIcon, classnames: cx, addMode} = this.props;
let data = this.props.data; let data = this.props.data;
const {value, addTop} = this.state;
const value = this.state.value;
return ( return (
<div className={cx(`Tree ${className || ''}`)}> <div className={cx(`Tree ${className || ''}`)}>
{data && data.length ? ( {data && data.length ? (
@ -648,6 +669,23 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
</span> </span>
</label> </label>
</a> </a>
{addMode ? (
<div className={cx('Tree-addTop')}>
{!addTop ? (
<p onClick={() => this.addItem(null, false)}>
<i className="fa fa-plus"></i>
<span></span>
</p>
) : null }
{addTop ? (
<div className={cx('Tree-addTop-input')}>
<input onChange={(e) => this.onChangeAddItem(e.currentTarget.value)}/>
<i className="fa fa-check" onClick={this.confirmAddItem}></i>
<i className="fa fa-close" onClick={this.cancelAddItem}></i>
</div>
) : null}
</div>
) : null}
<ul className={cx('Tree-sublist')}>{this.renderList(data, value, false).dom}</ul> <ul className={cx('Tree-sublist')}>{this.renderList(data, value, false).dom}</ul>
</li> </li>
)} )}

View File

@ -130,7 +130,7 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
} }
@autobind @autobind
openAddDialog(parent: Option) { openAddDialog(parent: Option | null) {
this.setState({ this.setState({
isAddModalOpened: true, isAddModalOpened: true,
parent parent