mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:48:13 +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)
|
更多用法,见 [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) =>
|
targetRef = (ref: any) =>
|
||||||
(this.target = ref ? (findDOMNode(ref) as HTMLElement) : null);
|
(this.target = ref ? (findDOMNode(ref) as HTMLElement) : null);
|
||||||
|
|
||||||
|
/** source数据源是否已加载 */
|
||||||
|
sourceLoaded: boolean = false;
|
||||||
|
|
||||||
constructor(props: TreeSelectProps) {
|
constructor(props: TreeSelectProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@ -183,7 +186,6 @@ export default class TreeSelectControl extends React.Component<
|
|||||||
leading: false
|
leading: false
|
||||||
});
|
});
|
||||||
this.handleInputKeyDown = this.handleInputKeyDown.bind(this);
|
this.handleInputKeyDown = this.handleInputKeyDown.bind(this);
|
||||||
|
|
||||||
this.loadRemote = debouce(this.loadRemote.bind(this), 250, {
|
this.loadRemote = debouce(this.loadRemote.bind(this), 250, {
|
||||||
trailing: true,
|
trailing: true,
|
||||||
leading: false
|
leading: false
|
||||||
@ -194,6 +196,10 @@ export default class TreeSelectControl extends React.Component<
|
|||||||
this.loadRemote('');
|
this.loadRemote('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.sourceLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
open(fn?: () => void) {
|
open(fn?: () => void) {
|
||||||
if (this.props.disabled) {
|
if (this.props.disabled) {
|
||||||
return;
|
return;
|
||||||
@ -228,7 +234,11 @@ export default class TreeSelectControl extends React.Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleKeyPress(e: React.KeyboardEvent) {
|
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);
|
this.handleOutClick(e as any);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
@ -353,9 +363,15 @@ export default class TreeSelectControl extends React.Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadRemote(input: string) {
|
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;
|
return;
|
||||||
} else if (!env || !env.fetcher) {
|
} else if (!env || !env.fetcher) {
|
||||||
throw new Error('fetcher is required');
|
throw new Error('fetcher is required');
|
||||||
|
Loading…
Reference in New Issue
Block a user