Skip to content

Commit aa162af

Browse files
authoredApr 12, 2022
feat(Tree): 新增Tree组件 disabled 属性 #759 (#765)
1 parent 1c26166 commit aa162af

File tree

4 files changed

+178
-6
lines changed

4 files changed

+178
-6
lines changed
 

‎packages/react-tree/README.md

+138-1
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,132 @@ const Demo = () => (
399399
ReactDOM.render(<Demo />, _mount_);
400400
```
401401

402+
### 禁用选项
403+
404+
<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
405+
```jsx
406+
import ReactDOM from 'react-dom';
407+
import { Tree, Card, Row, Col, Icon } from 'uiw';
408+
409+
const data = [
410+
{
411+
label: '湖北省',
412+
key: '0-0-0',
413+
children:[
414+
{
415+
label: '武汉市',
416+
disabled: true,
417+
key: '0-1-0',
418+
children:[
419+
{ label: '新洲区', key: '0-1-1' },
420+
{ label: '武昌区', key: '0-1-2' },
421+
{
422+
label: '汉南区',
423+
key: '0-1-3',
424+
children:[
425+
{ label: '汉南区1', key: '0-1-3-1' },
426+
{ label: '汉南区2', key: '0-1-3-2' },
427+
{ label: '汉南区3', key: '0-1-3-3' },
428+
]
429+
},
430+
]
431+
},
432+
{ label: '黄冈市', key: '0-2-0' },
433+
{
434+
label: '黄石市',
435+
key: '0-3-0',
436+
children:[
437+
{ label: '青山区', key: '0-3-1' },
438+
{ label: '黄陂区', key: '0-3-2' },
439+
{ label: '青山区', key: '0-3-3' },
440+
]
441+
},
442+
]
443+
},
444+
{
445+
label: '上海市',
446+
key: '1-0-0',
447+
children:[
448+
{ label: '黄浦区', key: '1-0-1' },
449+
{ label: '卢湾区', key: '1-0-2' },
450+
{
451+
label: '徐汇区',
452+
key: '1-0-3',
453+
children:[
454+
{ label: '半淞园路街道', key: '1-1-0' },
455+
{ label: '南京东路街道', key: '1-2-0' },
456+
{ label: '外滩街道', key: '1-3-0' },
457+
]
458+
},
459+
]
460+
},
461+
{
462+
label: '北京市',
463+
key: '2-0-0',
464+
children:[
465+
{ label: '东城区', key: '2-1-0' },
466+
{ label: '西城区', key: '2-2-0' },
467+
{
468+
label: '崇文区',
469+
key: '2-3-0',
470+
children:[
471+
{ label: '东花市街道', key: '2-3-1' },
472+
{ label: '体育馆路街道', key: '2-3-2' },
473+
{ label: '前门街道', key: '2-3-3' },
474+
]
475+
},
476+
]
477+
}
478+
];
479+
480+
const Demo = () => (
481+
<div>
482+
<Row gutter={10}>
483+
<Col fixed>
484+
<Card title="基础使用">
485+
<Tree data={data} />
486+
</Card>
487+
</Col>
488+
<Col fixed>
489+
<Card title="自定义图标">
490+
<Tree
491+
data={data}
492+
renderTitle={(item, { selected, noChild, disabledStyle }) => (
493+
<>
494+
<Icon style={{ display: '-webkit-inline-box', ...disabledStyle }} type={noChild ? 'smile-o' : 'apple'} />
495+
<span style={disabledStyle}>{item.label}</span>
496+
</>
497+
)}
498+
/>
499+
</Card>
500+
</Col>
501+
<Col fixed>
502+
<Card title="自定义选中效果">
503+
<Tree
504+
data={data}
505+
renderTitle={(item, { selected, isHalfChecked, disabledStyle, disabledClass }) => {
506+
if(isHalfChecked) {
507+
return (
508+
<><Icon type="minus-square-o" style={{ color: 'green', ...disabledStyle }} /> <span className={disabledClass} >{item.label}</span></>
509+
);
510+
}
511+
if (selected) {
512+
return (
513+
<><Icon type="check-square-o" style={{ color: 'green', ...disabledStyle }} /> <span className={disabledClass} >{item.label}</span></>
514+
);
515+
}
516+
return (
517+
<><Icon type="square-o" style={{ color: '#b6b6b6',...disabledStyle }} /> <span className={disabledClass} >{item.label}</span></>
518+
);
519+
}}
520+
/>
521+
</Card>
522+
</Col>
523+
</Row>
524+
</div>
525+
)
526+
ReactDOM.render(<Demo />, _mount_);
527+
```
402528

403529
### 连接线
404530

@@ -798,10 +924,21 @@ ReactDOM.render(<Demo />, _mount_);
798924
| checkStrictly | 子节点受父节点控制设置 `true`,需要配合 `multiple` 参数使用。 | Boolean | `false` |
799925
| multiple | 支持点选多个节点 | Boolean | `false` |
800926
| icon | 重新定义,展开收缩图标,当为函数时视为自定义图标,并展示非折叠项的图标。 | ~~Function(data: object, noChild: bool)/String/Node~~ `@3.4.0+` Function(data: object, { selected: bool, noChild: bool })/String/Node| - |
801-
| renderTitle | 重新定义每个标题节点的显示 | ~~Function(item, selected: bool, noChild: bool)~~ `@3.4.0+` Function(item: TreeData, node?: { selected?: boolean, noChild?: boolean, isHalfChecked?: boolean, openKeys?: TreeProps['openKeys'], selectedKeys?: TreeProps['selectedKeys'] }) => React.ReactElement; | - |
927+
| renderTitle | 重新定义每个标题节点的显示 | ~~Function(item, selected: bool, noChild: bool)~~ `@3.4.0+` Function(item: TreeData, node?: Node) => React.ReactElement; | - |
802928
| onSelected | 点击选择树节点触发 | Function(selectedKeys: array, key, selected: bool, data, e) | - |
803929
| onExpand | 展开/收起节点时触发 | Function(key, expanded: bool, data, evn) | - |
804930

931+
## Node Type
932+
| 参数 | 类型 | 版本 |
933+
|--------- |-------- |-------- |
934+
| selected | boolean | - |
935+
| noChild | boolean | - |
936+
| isHalfChecked | boolean | `@3.4.0+` |
937+
| openKeys | Props['openKeys'] | `@3.4.0+` |
938+
| selectedKeys | Props['selectedKeys'] | `@3.4.0+` |
939+
| disabled | boolean | `@4.20.0+` |
940+
| disabledClass | string | `@4.20.0+` |
941+
| disabledStyle | React.CSSProperties | `@4.20.0+` |
805942
### data
806943

807944
```json

‎packages/react-tree/src/TreeNode.tsx

+30-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ interface TreeNodeIconProps {
1111
selectedKeys: TreeNodeProps['selectedKeys'];
1212
}
1313

14+
interface DisabledObj {
15+
onClick?: (item: TreeData, evn: React.MouseEvent<HTMLElement, MouseEvent>) => void;
16+
disabled: string | null;
17+
disabledMouse: string | null;
18+
disabledClass?: string;
19+
disabledStyle?: React.CSSProperties;
20+
}
1421
interface TreeNodeProps<T = (data: TreeData, props: TreeNodeIconProps) => IconProps['type']> extends IProps {
1522
data: TreeData[];
1623
level: number;
@@ -27,7 +34,8 @@ interface TreeNodeProps<T = (data: TreeData, props: TreeNodeIconProps) => IconPr
2734
onItemSelected?: (item: TreeData, evn: React.MouseEvent<HTMLElement>) => void;
2835
}
2936

30-
const Label = ({ label }: { label: React.ReactNode }) => useMemo(() => <span>{label}</span>, [label]);
37+
const Label = ({ label, className }: { label: React.ReactNode; className?: string }) =>
38+
useMemo(() => <span className={className}>{label}</span>, [label]);
3139

3240
export default function TreeNode<T>(props: TreeNodeProps<T>) {
3341
const {
@@ -48,7 +56,6 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
4856
...other
4957
} = props;
5058
let isOpen = false;
51-
5259
const node = React.useRef<HTMLUListElement>(null);
5360

5461
if (parent && (parent.key || parent.key === 0)) {
@@ -110,6 +117,20 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
110117
const childKeys = noChild ? [] : getChildKeys(item.children);
111118
const checkedKeys = selectedKeys ? selectedKeys.filter((key) => childKeys.indexOf(key) > -1) : [];
112119
const isHalfChecked = checkedKeys.length > 0 && childKeys.length !== checkedKeys.length;
120+
const disabledObj: DisabledObj = {
121+
onClick: onItemSelected,
122+
disabled: null,
123+
disabledMouse: null,
124+
disabledClass: undefined,
125+
disabledStyle: undefined,
126+
};
127+
if (item.disabled) {
128+
disabledObj.onClick = undefined;
129+
disabledObj.disabled = 'disabled';
130+
disabledObj.disabledMouse = `${prefixCls}-disabled-mouse`;
131+
disabledObj.disabledClass = `${prefixCls}-disabled-ele`;
132+
disabledObj.disabledStyle = { color: '#00000040' };
133+
}
113134
return (
114135
<li key={idx} style={{ display: item.hideNode ? 'none' : 'block' }}>
115136
<div className={`${prefixCls}-label`}>
@@ -132,11 +153,12 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
132153
/>
133154
</span>
134155
<div
135-
onClick={(evn) => onItemSelected(item, evn)}
156+
onClick={(evn) => disabledObj.onClick?.(item, evn)}
136157
className={[
137158
`${prefixCls}-title`,
138159
selected && isSelected ? 'selected' : null,
139-
item.disabled ? 'disabled' : null,
160+
disabledObj.disabled,
161+
disabledObj.disabledMouse,
140162
]
141163
.filter(Boolean)
142164
.join(' ')
@@ -149,9 +171,12 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
149171
openKeys,
150172
isHalfChecked,
151173
selectedKeys,
174+
disabled: item.disabled,
175+
disabledClass: disabledObj.disabledClass,
176+
disabledStyle: disabledObj.disabledStyle,
152177
})
153178
) : (
154-
<Label label={item.label} />
179+
<Label label={item.label} className={disabledObj.disabledClass} />
155180
)}
156181
</div>
157182
</div>

‎packages/react-tree/src/index.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export type TreeRenderTitleNode = {
1010
isHalfChecked?: boolean;
1111
openKeys?: TreeProps['openKeys'];
1212
selectedKeys?: TreeProps['selectedKeys'];
13+
disabled?: boolean;
14+
disabledClass?: string;
15+
disabledStyle?: React.CSSProperties;
1316
};
1417

1518
export interface TreeProps extends IProps, Omit<HTMLDivProps, 'onChange'> {
@@ -54,6 +57,7 @@ export interface TreeData {
5457
children?: TreeData[];
5558
hideNode?: boolean;
5659
key?: string | number;
60+
disabled?: boolean;
5761
[keyName: string]: any;
5862
}
5963

‎packages/react-tree/src/style/index.less

+6
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
vertical-align: middle;
6262
}
6363
}
64+
&-disabled-mouse {
65+
cursor: not-allowed;
66+
}
67+
&-disabled-ele {
68+
color: #00000040;
69+
}
6470
&-title.selected {
6571
background-color: #d5e8fc;
6672
}

0 commit comments

Comments
 (0)
Please sign in to comment.