Skip to content

Commit cf6460f

Browse files
author
liyuan-meng
committed
✨[TreeSelect]支持设置弹出位置
1 parent a104032 commit cf6460f

3 files changed

Lines changed: 240 additions & 31 deletions

File tree

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
---
2+
order: 2
3+
title: 多层单选与多选
4+
desc: 与Tree结合的树下拉
5+
---
6+
7+
```jsx
8+
import React from 'react';
9+
import { TreeSelect } from 'cloud-react';
10+
11+
class TreeSelectDemo extends React.Component {
12+
treeData = [
13+
{
14+
id: 11,
15+
name: '禁止删除节点',
16+
pId: 1,
17+
disableRemove: true,
18+
children: [
19+
{
20+
id: 113,
21+
name: '删除三个',
22+
pId: 11,
23+
children: [
24+
{
25+
id: 1131,
26+
name: '禁止删除节点31',
27+
pId: 113,
28+
children: []
29+
},
30+
{
31+
id: 1132,
32+
name: '禁止删除节点32',
33+
pId: 113,
34+
children: [
35+
{
36+
id: 11321,
37+
name: '禁止删除节点321',
38+
pId: 1132,
39+
children: []
40+
}
41+
]
42+
}
43+
]
44+
},
45+
{
46+
id: 114,
47+
name: '禁止删除节点4',
48+
pId: 11,
49+
children: []
50+
}
51+
]
52+
},
53+
{
54+
id: 14,
55+
name: '未分类',
56+
pId: 1,
57+
disableRemove: true,
58+
disableAdd: true,
59+
disableRename: true,
60+
children: []
61+
}
62+
];
63+
64+
constructor(props) {
65+
super(props);
66+
67+
this.state = {
68+
selectedNodes: [
69+
{
70+
id: 11321,
71+
name: '禁止删除节点321',
72+
pId: 1132,
73+
children: []
74+
}
75+
],
76+
confirmNodes: [],
77+
singleNodes: [
78+
{
79+
id: 11321,
80+
name: '禁止删除节点321',
81+
pId: 1132,
82+
children: []
83+
}
84+
]
85+
};
86+
setTimeout(() => {
87+
this.setState({
88+
confirmNodes: [this.treeData[0]]
89+
});
90+
}, 1000);
91+
92+
}
93+
94+
handleChange = (node, selectedNodes) => {
95+
console.log(node, selectedNodes);
96+
97+
this.setState({
98+
selectedNodes
99+
});
100+
};
101+
102+
handleConfirmChange = (node, selectedNodes) => {
103+
console.log(node, selectedNodes);
104+
105+
this.setState({
106+
confirmNodes: selectedNodes
107+
});
108+
};
109+
110+
onOk = (node, selectedNodes) => {
111+
console.log(node, selectedNodes);
112+
113+
this.setState({
114+
confirmNodes: selectedNodes
115+
});
116+
};
117+
118+
onChangeSingle = (node, selectedNodes) => {
119+
console.log(node, selectedNodes);
120+
121+
this.setState({
122+
singleNodes: selectedNodes
123+
});
124+
};
125+
126+
render() {
127+
return (
128+
<div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
129+
<div>
130+
<h5>左上</h5>
131+
<TreeSelect
132+
allowClear
133+
position="top"
134+
type="single"
135+
isUnfold
136+
containParentNode
137+
placeholder="选择一个选项"
138+
style={{ width: 260 }}
139+
dropdownStyle={{ width: 328 }}
140+
dataSource={this.treeData}
141+
value={this.state.singleNodes}
142+
onChange={this.onChangeSingle}
143+
/>
144+
</div>
145+
<div>
146+
<h5>左下</h5>
147+
<TreeSelect
148+
allowClear
149+
position="bottom"
150+
type="single"
151+
isUnfold
152+
containParentNode
153+
placeholder="选择一个选项"
154+
style={{ width: 260 }}
155+
dropdownStyle={{ width: 328 }}
156+
dataSource={this.treeData}
157+
value={this.state.singleNodes}
158+
onChange={this.onChangeSingle}
159+
/>
160+
</div>
161+
<div>
162+
<h5>右上</h5>
163+
<TreeSelect
164+
allowClear
165+
position="top"
166+
type="single"
167+
isUnfold
168+
containParentNode
169+
placeholder="选择一个选项"
170+
style={{ width: 260 }}
171+
dropdownStyle={{ width: 328, right: 0 }}
172+
dataSource={this.treeData}
173+
value={this.state.singleNodes}
174+
onChange={this.onChangeSingle}
175+
/>
176+
</div>
177+
<div>
178+
<h5>右下</h5>
179+
<TreeSelect
180+
allowClear
181+
position="bottom"
182+
type="single"
183+
isUnfold
184+
containParentNode
185+
placeholder="选择一个选项"
186+
style={{ width: 260 }}
187+
dropdownStyle={{ width: 328, right: 0 }}
188+
dataSource={this.treeData}
189+
value={this.state.singleNodes}
190+
onChange={this.onChangeSingle}
191+
/>
192+
</div>
193+
</div>
194+
);
195+
}
196+
}
197+
198+
export default TreeSelectDemo;
199+
```

src/components/tree-select/index.js

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -149,33 +149,30 @@ class TreeSelect extends Component {
149149
}
150150

151151
positionPop = () => {
152-
const {
153-
props: { isAppendToBody, position },
154-
selectedContainerStyle: { left, top, bottom, height },
155-
optionsNodeStyle: { height: optionsHeight },
156-
} = this;
157-
const isBottomDistanceEnough =
158-
bottom + optionsHeight < this.document.documentElement.clientHeight;
159-
const isLocationTop =
160-
optionsHeight < top && !isBottomDistanceEnough && position === 'auto';
161-
const borderTop = isLocationTop ? '1px solid #d9d9d9' : null;
162-
if (isAppendToBody) {
163-
this.setState({
164-
style: {
165-
position: 'fixed',
166-
left: `${left}px`,
167-
top: isLocationTop ? `${top - optionsHeight}px` : `${bottom}px`,
168-
borderTop,
169-
},
170-
});
171-
} else {
172-
this.setState({
173-
style: {
174-
top: isLocationTop ? `${-optionsHeight - 4}px` : `${height + 4}px`,
175-
borderTop,
176-
},
177-
});
178-
}
152+
setTimeout(() => {
153+
const {
154+
props: { isAppendToBody, position },
155+
selectedContainerStyle: { left, top, bottom, height },
156+
optionsNodeStyle: { height: optionsHeight },
157+
} = this;
158+
const isBottomDistanceEnough = bottom + optionsHeight < this.document.documentElement.clientHeight;
159+
const isLocationTop = position === 'top' || optionsHeight < top && !isBottomDistanceEnough && position === 'auto';
160+
if (isAppendToBody) {
161+
this.setState({
162+
style: {
163+
position: 'fixed',
164+
left: `${left}px`,
165+
top: isLocationTop ? `${top - optionsHeight}px` : `${bottom + 4}px`,
166+
},
167+
});
168+
} else {
169+
this.setState({
170+
style: {
171+
top: isLocationTop ? `${-optionsHeight - 4}px` : `${height + 4}px`,
172+
},
173+
});
174+
}
175+
});
179176
};
180177

181178
handleClick = (e) => {
@@ -345,6 +342,8 @@ class TreeSelect extends Component {
345342
allowClear,
346343
style,
347344
className,
345+
dropdownStyle,
346+
dropdownClassName,
348347
isAppendToBody,
349348
searchable,
350349
} = this.props;
@@ -358,9 +357,9 @@ class TreeSelect extends Component {
358357
);
359358
const treeOptionsContainer = open ? (
360359
<div
361-
className={`${selector}-container`}
360+
className={`${selector}-container ${dropdownClassName}`}
362361
ref={this.optionsNode}
363-
style={{ ...popupStyle, minWidth: width }}
362+
style={{ ...popupStyle, minWidth: width, ...dropdownStyle }}
364363
>
365364
{this.renderTreeNode()}
366365
</div>
@@ -423,6 +422,9 @@ TreeSelect.propTypes = {
423422
onReset: PropTypes.func,
424423
searchInBox: PropTypes.bool,
425424
maxTagCount: PropTypes.number,
425+
dropdownStyle: PropTypes.object,
426+
dropdownClassName: PropTypes.string,
427+
position: PropTypes.oneOf(['top', 'bottom', 'auto']),
426428
};
427429

428430
TreeSelect.defaultProps = {
@@ -450,6 +452,9 @@ TreeSelect.defaultProps = {
450452
onReset: noop,
451453
searchInBox: false,
452454
maxTagCount: undefined,
455+
dropdownStyle: {},
456+
dropdownClassName: '',
457+
position: 'bottom',
453458
};
454459

455460
export default TreeSelect;

src/components/tree-select/index.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ group:
3939
| onSelectClose | 下拉选择框关闭的时候回调此函数 | function | - |
4040
| searchInBox | 搜索框在外侧 | boolean | false |
4141
| maxTagCount | 多选下拉最多显示多少个tag | number | - |
42+
| position | 下拉框定位:`top` `bottom` `auto`(是否启用自动定位,如需使用可设置为`auto`| string | `bottom` |
43+
| dropdownClassName | 下拉框类名 | string | - |
44+
| dropdownStyle | 下拉框样式 | object | {} |
4245

4346
#### `single = true`,单选下拉树时候支持的配置
4447
| 属性 | 说明 | 类型 | 默认值 |
@@ -61,7 +64,6 @@ group:
6164
| onReset | 重置回调 | function | - |
6265
| containParentNode | 结果是否包含各个父节点 | boolean | false |
6366

64-
6567
树的更多属性配置可参考 **Tree** 组件
6668

6769
### 代码演示
@@ -73,5 +75,8 @@ group:
7375
<embed src="@components/tree-select/demos/searchable.md" />
7476

7577
### 不与Tree结合的树下拉
76-
<embed src="@components/tree-select/demos/basic-tree-select.md" />
78+
<embed src="@components/tree-select/demos/basic-tree-select.md" />
79+
80+
### 弹出位置
81+
<embed src="@components/tree-select/demos/position.md" />
7782

0 commit comments

Comments
 (0)