mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:58:05 +08:00
fix: ChainedSelect 组件多展示一个空 Select (#6166)
This commit is contained in:
parent
bb57649d28
commit
980555d8dd
@ -2,4 +2,9 @@
|
||||
.#{$ns}Select {
|
||||
margin-right: var(--gap-xs);
|
||||
}
|
||||
|
||||
&-spinner {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ exports[`Renderer:chained-select 1`] = `
|
||||
<div
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-labelledby="downshift-2-label"
|
||||
aria-labelledby="downshift-1-label"
|
||||
class="cxd-Select cxd-Select--inline"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
@ -239,7 +239,7 @@ exports[`Renderer:chained-select 1`] = `
|
||||
<div
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-labelledby="downshift-3-label"
|
||||
aria-labelledby="downshift-2-label"
|
||||
class="cxd-Select cxd-Select--inline"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
@ -265,7 +265,7 @@ exports[`Renderer:chained-select 1`] = `
|
||||
<div
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-labelledby="downshift-4-label"
|
||||
aria-labelledby="downshift-3-label"
|
||||
class="cxd-Select cxd-Select--inline"
|
||||
role="combobox"
|
||||
tabindex="0"
|
||||
@ -289,128 +289,12 @@ exports[`Renderer:chained-select 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
aria-expanded="true"
|
||||
aria-haspopup="listbox"
|
||||
aria-labelledby="downshift-5-label"
|
||||
aria-owns="downshift-5-menu"
|
||||
class="cxd-Select cxd-Select--inline is-opened has-popover"
|
||||
role="combobox"
|
||||
style="position: relative;"
|
||||
tabindex="0"
|
||||
class="cxd-Spinner in cxd-ChainedSelectControl-spinner"
|
||||
data-testid="spinner"
|
||||
>
|
||||
<div
|
||||
class="cxd-Select-valueWrap"
|
||||
>
|
||||
<div
|
||||
class="cxd-Select-placeholder"
|
||||
>
|
||||
请选择
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="cxd-Select-arrow"
|
||||
>
|
||||
<icon-mock
|
||||
classname="icon icon-right-arrow-bold"
|
||||
icon="right-arrow-bold"
|
||||
/>
|
||||
</span>
|
||||
<div
|
||||
class="cxd-PopOver cxd-Select-popover cxd-PopOver--leftBottomLeftTop"
|
||||
style="display: block; width: 0px; left: 0px; top: 0px; position: relative;"
|
||||
theme="cxd"
|
||||
>
|
||||
<div
|
||||
class="cxd-PopOver-overlay"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Select-menu"
|
||||
>
|
||||
<div
|
||||
class="cxd-Select-noResult"
|
||||
>
|
||||
未找到任何结果
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="resize-sensor"
|
||||
style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-expand"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
style="position: absolute; left: 0px; top: 0px; width: 10px; height: 10px;"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-shrink"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
style="position: absolute; left: 0; top: 0; width: 200%; height: 200%"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-appear"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;animation-name: apearSensor; animation-duration: 0.2s;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="resize-sensor"
|
||||
style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-expand"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
style="position: absolute; left: 0px; top: 0px; width: 10px; height: 10px;"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-shrink"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
style="position: absolute; left: 0; top: 0; width: 200%; height: 200%"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-appear"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;animation-name: apearSensor; animation-duration: 0.2s;"
|
||||
/>
|
||||
</div>
|
||||
class="cxd-Spinner-icon cxd-Spinner-icon--sm cxd-Spinner-icon--default"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -116,8 +116,12 @@ test('Renderer:chained-select', async () => {
|
||||
await waitFor(() => {
|
||||
expect(fetcher).toBeCalledTimes(5);
|
||||
});
|
||||
fireEvent.click(getByText('请选择'));
|
||||
expect(getByText('未找到任何结果')).toBeInTheDocument();
|
||||
|
||||
expect(container).not.toHaveTextContent('请选择');
|
||||
expect(
|
||||
container.querySelectorAll('.cxd-ChainedSelectControl > .cxd-Select')!
|
||||
.length
|
||||
).toBe(4);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
FormOptionsControl,
|
||||
resolveEventData
|
||||
} from 'amis-core';
|
||||
import {Select} from 'amis-ui';
|
||||
import {Select, Spinner} from 'amis-ui';
|
||||
import {Api} from 'amis-core';
|
||||
import {isEffectiveApi} from 'amis-core';
|
||||
import {isMobile, createObject} from 'amis-core';
|
||||
@ -15,6 +15,7 @@ import {ActionObject} from 'amis-core';
|
||||
import {FormOptionsSchema} from '../../Schema';
|
||||
import {supportStatic} from './StaticHoc';
|
||||
import find from 'lodash/find';
|
||||
import {isEmpty} from 'lodash';
|
||||
|
||||
/**
|
||||
* 链式下拉框
|
||||
@ -36,13 +37,15 @@ export interface ChainedSelectProps
|
||||
| 'inputClassName'
|
||||
> {}
|
||||
|
||||
export interface StackItem {
|
||||
options: Array<Option>;
|
||||
parentId: any;
|
||||
loading: boolean;
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
export interface SelectState {
|
||||
stack: Array<{
|
||||
options: Array<Option>;
|
||||
parentId: any;
|
||||
loading: boolean;
|
||||
visible?: boolean;
|
||||
}>;
|
||||
stack: Array<StackItem>;
|
||||
}
|
||||
|
||||
export default class ChainedSelectControl extends React.Component<
|
||||
@ -201,7 +204,7 @@ export default class ChainedSelectControl extends React.Component<
|
||||
options,
|
||||
parentId,
|
||||
loading: false,
|
||||
visible: !!options
|
||||
visible: Array.isArray(options) && !isEmpty(options)
|
||||
});
|
||||
|
||||
this.setState(
|
||||
@ -268,16 +271,13 @@ export default class ChainedSelectControl extends React.Component<
|
||||
delimiter
|
||||
} = this.props;
|
||||
|
||||
const allOptions = [
|
||||
{options, visible: true},
|
||||
...(this.state.stack || [])
|
||||
];
|
||||
const allOptions = [{options, visible: true}, ...(this.state.stack || [])];
|
||||
const valueArr = Array.isArray(value)
|
||||
? value.concat()
|
||||
: value && typeof value === 'string'
|
||||
? value.split(delimiter || ',')
|
||||
: [];
|
||||
|
||||
|
||||
if (valueArr?.length > 0) {
|
||||
displayValue = valueArr
|
||||
.map((value: any, index) => {
|
||||
@ -288,14 +288,19 @@ export default class ChainedSelectControl extends React.Component<
|
||||
if (!options || !options.length) {
|
||||
return value;
|
||||
}
|
||||
const selectedOption = find(options, (o) => value === o[valueField]) || {};
|
||||
const selectedOption =
|
||||
find(options, o => value === o[valueField]) || {};
|
||||
return selectedOption[labelField] ?? value;
|
||||
})
|
||||
.filter(v => v != null)
|
||||
.join(' > ');
|
||||
}
|
||||
|
||||
return <div className={cx(`${classPrefix}SelectStaticControl`, className)}>{displayValue}</div>;
|
||||
|
||||
return (
|
||||
<div className={cx(`${classPrefix}SelectStaticControl`, className)}>
|
||||
{displayValue}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@supportStatic()
|
||||
@ -322,6 +327,8 @@ export default class ChainedSelectControl extends React.Component<
|
||||
? value.split(delimiter || ',')
|
||||
: [];
|
||||
|
||||
const hasStackLoading = this.state.stack.find((a: StackItem) => a.loading);
|
||||
|
||||
const mobileUI = useMobileUI && isMobile();
|
||||
return (
|
||||
<div className={cx(`${ns}ChainedSelectControl`, className)}>
|
||||
@ -343,7 +350,8 @@ export default class ChainedSelectControl extends React.Component<
|
||||
/>
|
||||
|
||||
{this.state.stack.map(({options, loading, visible}, index) =>
|
||||
visible === false ? null : (
|
||||
// loading 中的选项不展示,避免没值再隐藏造成的闪烁,改用一个 Spinner 来展示 loading 状态
|
||||
visible === false || loading ? null : (
|
||||
<Select
|
||||
{...rest}
|
||||
useMobileUI={useMobileUI}
|
||||
@ -357,11 +365,17 @@ export default class ChainedSelectControl extends React.Component<
|
||||
options={Array.isArray(options) ? options : []}
|
||||
value={arr[index + 1]}
|
||||
onChange={this.handleChange.bind(this, index + 1)}
|
||||
loading={loading}
|
||||
inline
|
||||
/>
|
||||
)
|
||||
)}
|
||||
|
||||
{hasStackLoading && (
|
||||
<Spinner
|
||||
size="sm"
|
||||
className={cx(`${ns}ChainedSelectControl-spinner`)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user