mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
fix: Tree组件同时配置source & autoComplete时数据覆盖问题 (#6113)
This commit is contained in:
parent
31063fe68e
commit
7c2fcdfb6a
@ -300,6 +300,28 @@ order: 60
|
||||
}
|
||||
```
|
||||
|
||||
## 搜索选项
|
||||
|
||||
> `2.7.1` 及以上版本
|
||||
|
||||
配置`autoComplete`接口可以实现从远程数据搜索目标结果,搜索的关键字段为`term`,注意搜索的逻辑需要在服务端实现。
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type":"form",
|
||||
"api":"/api/mock2/form/saveForm",
|
||||
"body":[
|
||||
{
|
||||
"type":"tree-select",
|
||||
"name":"tree",
|
||||
"label":"Tree",
|
||||
"autoComplete":"/api/mock2/tree/search?term=$term",
|
||||
"source":"/api/mock2/tree/search"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 属性表
|
||||
|
||||
更多用法,见 [InputTree](./input-tree)
|
||||
|
183
mock/cfc/mock/tree/search.js
Normal file
183
mock/cfc/mock/tree/search.js
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @file tree/autoComplete
|
||||
* @desc 树形结构的自动搜索
|
||||
*/
|
||||
|
||||
const treeOptions = [
|
||||
{
|
||||
label: 'node-0',
|
||||
value: 'node-0',
|
||||
children: [
|
||||
{
|
||||
label: 'node-0-0',
|
||||
value: 'node-0-0',
|
||||
children: [
|
||||
{
|
||||
label: 'node-0-0-0',
|
||||
value: 'node-0-0-0',
|
||||
children: [
|
||||
{
|
||||
label: 'node-0-0-0-0',
|
||||
value: 'node-0-0-0-0'
|
||||
},
|
||||
{
|
||||
label: 'node-0-0-0-1',
|
||||
value: 'node-0-0-0-1'
|
||||
},
|
||||
{
|
||||
label: 'node-0-0-0-2',
|
||||
value: 'node-0-0-0-2'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'node-0-0-1',
|
||||
value: 'node-0-0-1',
|
||||
children: [
|
||||
{
|
||||
label: 'node-0-0-1-0',
|
||||
value: 'node-0-0-1-0'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'node-0-0-2',
|
||||
value: 'node-0-0-2',
|
||||
children: [
|
||||
{
|
||||
label: 'node-0-0-2-0',
|
||||
value: 'node-0-0-2-0'
|
||||
},
|
||||
{
|
||||
label: 'node-0-0-2-1',
|
||||
value: 'node-0-0-2-1'
|
||||
},
|
||||
{
|
||||
label: 'node-0-0-2-2',
|
||||
value: 'node-0-0-2-2'
|
||||
},
|
||||
{
|
||||
label: 'node-0-0-2-3',
|
||||
value: 'node-0-0-2-3'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'node-0-1',
|
||||
value: 'node-0-1',
|
||||
children: [
|
||||
{
|
||||
label: 'node-0-1-0',
|
||||
value: 'node-0-1-0',
|
||||
children: [
|
||||
{
|
||||
label: 'node-0-1-0-0',
|
||||
value: 'node-0-1-0-0'
|
||||
},
|
||||
{
|
||||
label: 'node-0-1-0-1',
|
||||
value: 'node-0-1-0-1'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'node-0-1-1',
|
||||
value: 'node-0-1-1',
|
||||
children: [
|
||||
{
|
||||
label: 'node-0-1-1-0',
|
||||
value: 'node-0-1-1-0'
|
||||
},
|
||||
{
|
||||
label: 'node-0-1-1-1',
|
||||
value: 'node-0-1-1-1'
|
||||
},
|
||||
{
|
||||
label: 'node-0-1-1-2',
|
||||
value: 'node-0-1-1-2'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'node-1',
|
||||
value: 'node-1',
|
||||
children: [
|
||||
{
|
||||
label: 'node-1-0',
|
||||
value: 'node-1-0'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'node-2',
|
||||
value: 'node-2'
|
||||
},
|
||||
{
|
||||
label: 'node-3',
|
||||
value: 'node-3',
|
||||
children: [
|
||||
{
|
||||
label: 'node-3-0',
|
||||
value: 'node-3-0',
|
||||
children: [
|
||||
{
|
||||
label: 'node-3-0-0',
|
||||
value: 'node-3-0-0'
|
||||
},
|
||||
{
|
||||
label: 'node-3-0-1',
|
||||
value: 'node-3-0-1'
|
||||
},
|
||||
{
|
||||
label: 'node-3-0-2',
|
||||
value: 'node-3-0-2'
|
||||
},
|
||||
{
|
||||
label: 'node-3-0-3',
|
||||
value: 'node-3-0-3'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
function searchNode(keyword) {
|
||||
const search = data => {
|
||||
const matched = [];
|
||||
|
||||
data.forEach(node => {
|
||||
if (node.value && ~node.value.indexOf(keyword)) {
|
||||
matched.push({...node});
|
||||
} else if (node.children) {
|
||||
const filtered = search(node.children);
|
||||
|
||||
if (filtered.length) {
|
||||
matched.push({...node, children: filtered});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return matched;
|
||||
};
|
||||
|
||||
return search(treeOptions);
|
||||
}
|
||||
|
||||
module.exports = function (req, res) {
|
||||
const term = req.query.term || '';
|
||||
|
||||
res.json({
|
||||
status: 0,
|
||||
msg: '',
|
||||
data: {
|
||||
options: term ? searchNode(term) : treeOptions
|
||||
}
|
||||
});
|
||||
};
|
@ -163,6 +163,9 @@ export default class TreeSelectControl extends React.Component<
|
||||
targetRef = (ref: any) =>
|
||||
(this.target = ref ? (findDOMNode(ref) as HTMLElement) : null);
|
||||
|
||||
/** source数据源是否已加载 */
|
||||
sourceLoaded: boolean = false;
|
||||
|
||||
constructor(props: TreeSelectProps) {
|
||||
super(props);
|
||||
|
||||
@ -183,7 +186,6 @@ export default class TreeSelectControl extends React.Component<
|
||||
leading: false
|
||||
});
|
||||
this.handleInputKeyDown = this.handleInputKeyDown.bind(this);
|
||||
|
||||
this.loadRemote = debouce(this.loadRemote.bind(this), 250, {
|
||||
trailing: true,
|
||||
leading: false
|
||||
@ -194,6 +196,10 @@ export default class TreeSelectControl extends React.Component<
|
||||
this.loadRemote('');
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.sourceLoaded = false;
|
||||
}
|
||||
|
||||
open(fn?: () => void) {
|
||||
if (this.props.disabled) {
|
||||
return;
|
||||
@ -228,7 +234,11 @@ export default class TreeSelectControl extends React.Component<
|
||||
}
|
||||
|
||||
handleKeyPress(e: React.KeyboardEvent) {
|
||||
if (e.key === ' ') {
|
||||
/**
|
||||
* 考虑到label/value中有空格的case
|
||||
* 这里使用组合键关闭 win:shift + space,mac:shift + space
|
||||
*/
|
||||
if (e.key === ' ' && e.shiftKey) {
|
||||
this.handleOutClick(e as any);
|
||||
e.preventDefault();
|
||||
}
|
||||
@ -353,9 +363,15 @@ export default class TreeSelectControl extends React.Component<
|
||||
}
|
||||
|
||||
async loadRemote(input: string) {
|
||||
const {autoComplete, env, data, setOptions, setLoading} = this.props;
|
||||
const {autoComplete, env, data, setOptions, setLoading, source} =
|
||||
this.props;
|
||||
|
||||
if (!isEffectiveApi(autoComplete, data)) {
|
||||
// 同时配置source和autoComplete时,首次渲染需要加载source数据
|
||||
if (
|
||||
!isEffectiveApi(autoComplete, data) ||
|
||||
(!input && isEffectiveApi(source) && !this.sourceLoaded)
|
||||
) {
|
||||
this.sourceLoaded = true;
|
||||
return;
|
||||
} else if (!env || !env.fetcher) {
|
||||
throw new Error('fetcher is required');
|
||||
|
Loading…
Reference in New Issue
Block a user