mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:58:07 +08:00
parent
eaa62a253e
commit
641f35ae37
@ -1405,14 +1405,32 @@ order: 2
|
|||||||
|
|
||||||
> 1.10.0 及以上版本
|
> 1.10.0 及以上版本
|
||||||
|
|
||||||
下拉框在数据量较大时(超过 200,可以通过 `virtualThreshold` 控制)会自动切换到虚拟渲染模式,如果选项的内容较长会导致内容重叠,这时需要设置 `itemHeight` 来避免。
|
下拉框在数据量较大时(超过 100,可以通过 `virtualThreshold` 控制)会自动切换到虚拟渲染模式,如果选项的内容较长会导致内容重叠,这时需要设置 `itemHeight` 来避免。
|
||||||
|
|
||||||
|
```schema: scope="body"
|
||||||
|
{
|
||||||
|
"type": "form",
|
||||||
|
"api": "/api/mock2/form/saveForm",
|
||||||
|
"debug": true,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"label": "虚拟列表选择",
|
||||||
|
"name": "virtual-select",
|
||||||
|
"clearable": true,
|
||||||
|
"searchable": true,
|
||||||
|
"source": "/api/mock2/form/getOptions?waitSeconds=1&size=200"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 属性表
|
## 属性表
|
||||||
|
|
||||||
除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置
|
除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置
|
||||||
|
|
||||||
| 属性名 | 类型 | 默认值 | 说明 |
|
| 属性名 | 类型 | 默认值 | 说明 |
|
||||||
| ---------------- | --------------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------- |
|
| ---------------- | --------------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------------- |
|
||||||
| options | `Array<object>`或`Array<string>` | | 选项组,供用户选择 |
|
| options | `Array<object>`或`Array<string>` | | 选项组,供用户选择 |
|
||||||
| source | [API](../../../docs/types/api) 或 [数据映射](../../../docs/concepts/data-mapping) | | 选项组源,可通过数据映射获取当前数据域变量、或者配置 API 对象 |
|
| source | [API](../../../docs/types/api) 或 [数据映射](../../../docs/concepts/data-mapping) | | 选项组源,可通过数据映射获取当前数据域变量、或者配置 API 对象 |
|
||||||
| multiple | `boolean` | `false` | 是否支持多选 |
|
| multiple | `boolean` | `false` | 是否支持多选 |
|
||||||
@ -1420,6 +1438,6 @@ order: 2
|
|||||||
| valueField | `boolean` | `"value"` | 标识选项中哪个字段是`value`值 |
|
| valueField | `boolean` | `"value"` | 标识选项中哪个字段是`value`值 |
|
||||||
| joinValues | `boolean` | `true` | 是否拼接`value`值 |
|
| joinValues | `boolean` | `true` | 是否拼接`value`值 |
|
||||||
| extractValue | `boolean` | `false` | 是否将`value`值抽取出来组成新的数组,只有在`joinValues`是`false`是生效 |
|
| extractValue | `boolean` | `false` | 是否将`value`值抽取出来组成新的数组,只有在`joinValues`是`false`是生效 |
|
||||||
| itemHeight | `number` | | 每个选项的高度,用于虚拟渲染 |
|
| itemHeight | `number` | `32` | 每个选项的高度,用于虚拟渲染 |
|
||||||
| virtualThreshold | `number` | | 在选项数量超过多少时开启虚拟渲染 |
|
| virtualThreshold | `number` | `100` | 在选项数量超过多少时开启虚拟渲染 |
|
||||||
| valuesNoWrap | `boolean` | `false` | 默认情况下多选所有选项都会显示,通过这个可以最多显示一行,超出的部分变成 ... |
|
| valuesNoWrap | `boolean` | `false` | 默认情况下多选所有选项都会显示,通过这个可以最多显示一行,超出的部分变成 ... |
|
||||||
|
42
mock/cfc/mock/form/getOptions.js
Normal file
42
mock/cfc/mock/form/getOptions.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
module.exports = function (req, res) {
|
||||||
|
const size =
|
||||||
|
req.query.size && typeof Number(req.query.size) === 'number'
|
||||||
|
? Math.ceil(req.query.size)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
const customOptions =
|
||||||
|
size > 0
|
||||||
|
? Array.from({length: size}, (item, index) => ({
|
||||||
|
label: 'Option ' + index,
|
||||||
|
value: index.toString()
|
||||||
|
}))
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const defaultOptions = [
|
||||||
|
{label: 'Option A', value: 'a'},
|
||||||
|
{label: 'Option B', value: 'b'},
|
||||||
|
{label: 'Option C', value: 'c'},
|
||||||
|
{label: 'Option D', value: 'd'},
|
||||||
|
{label: 'Option E', value: 'e'},
|
||||||
|
{label: 'Option F', value: 'f'},
|
||||||
|
{label: 'Option G', value: 'g'},
|
||||||
|
{label: 'Option H', value: 'h'},
|
||||||
|
{label: 'Option I', value: 'i'},
|
||||||
|
{label: 'Option J', value: 'j'},
|
||||||
|
{label: 'Option K', value: 'k'},
|
||||||
|
{label: 'Option L', value: 'l'},
|
||||||
|
{label: 'Option M', value: 'm'},
|
||||||
|
{label: 'Option N', value: 'n'},
|
||||||
|
{label: 'Option O', value: 'o'},
|
||||||
|
{label: 'Option P', value: 'p'},
|
||||||
|
{label: 'Option Q', value: 'q'}
|
||||||
|
];
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
status: 0,
|
||||||
|
msg: 'ok',
|
||||||
|
data: {
|
||||||
|
options: customOptions.length > 0 ? customOptions : defaultOptions
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"status": 0,
|
|
||||||
"msg": "ok",
|
|
||||||
"data": {
|
|
||||||
"options": [
|
|
||||||
{"label": "Option A", "value": "a"},
|
|
||||||
{"label": "Option B", "value": "b"},
|
|
||||||
{"label": "Option C", "value": "c"},
|
|
||||||
{"label": "Option D", "value": "d"},
|
|
||||||
{"label": "Option E", "value": "e"},
|
|
||||||
{"label": "Option F", "value": "f"},
|
|
||||||
{"label": "Option G", "value": "g"},
|
|
||||||
{"label": "Option H", "value": "h"},
|
|
||||||
{"label": "Option I", "value": "i"},
|
|
||||||
{"label": "Option J", "value": "j"},
|
|
||||||
{"label": "Option K", "value": "k"},
|
|
||||||
{"label": "Option L", "value": "l"},
|
|
||||||
{"label": "Option M", "value": "m"},
|
|
||||||
{"label": "Option N", "value": "n"},
|
|
||||||
{"label": "Option O", "value": "o"},
|
|
||||||
{"label": "Option P", "value": "p"},
|
|
||||||
{"label": "Option Q", "value": "q"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
import React = require('react');
|
import React = require('react');
|
||||||
import {NotFound} from 'amis-ui';
|
import NotFound from '../src/components/404';
|
||||||
import * as renderer from 'react-test-renderer';
|
import * as renderer from 'react-test-renderer';
|
||||||
import {render, fireEvent, cleanup} from '@testing-library/react';
|
import {render, fireEvent, cleanup} from '@testing-library/react';
|
||||||
|
|
||||||
|
@ -81,6 +81,8 @@
|
|||||||
|
|
||||||
.#{$ns}PopOver.#{$ns}Select-popover {
|
.#{$ns}PopOver.#{$ns}Select-popover {
|
||||||
.#{$ns}Select-menu {
|
.#{$ns}Select-menu {
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
.#{$ns}Select-option {
|
.#{$ns}Select-option {
|
||||||
height: px2rem(32px);
|
height: px2rem(32px);
|
||||||
line-height: px2rem(22px);
|
line-height: px2rem(22px);
|
||||||
|
@ -9,6 +9,7 @@ import {uncontrollable} from 'amis-core';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import isInteger from 'lodash/isInteger';
|
import isInteger from 'lodash/isInteger';
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
|
import merge from 'lodash/merge';
|
||||||
import VirtualList from './virtual-list';
|
import VirtualList from './virtual-list';
|
||||||
import Overlay from './Overlay';
|
import Overlay from './Overlay';
|
||||||
import PopOver from './PopOver';
|
import PopOver from './PopOver';
|
||||||
@ -413,7 +414,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||||||
inputValue: '',
|
inputValue: '',
|
||||||
highlightedIndex: -1,
|
highlightedIndex: -1,
|
||||||
selection: value2array(props.value, props),
|
selection: value2array(props.value, props),
|
||||||
itemHeight: 35,
|
itemHeight: 32 /** Select选项高度保持一致 */,
|
||||||
pickerSelectItem: ''
|
pickerSelectItem: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -728,7 +729,9 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
menuItemRef(ref: any) {
|
menuItemRef(ref: any) {
|
||||||
ref && this.setState({itemHeight: ref.offsetHeight});
|
if (ref && typeof ref.offsetHeight === 'number' && ref > 0) {
|
||||||
|
this.setState({itemHeight: ref.offsetHeight});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderValue({inputValue, isOpen}: ControllerStateAndHelpers<any>) {
|
renderValue({inputValue, isOpen}: ControllerStateAndHelpers<any>) {
|
||||||
@ -946,7 +949,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||||||
hideSelected,
|
hideSelected,
|
||||||
renderMenu,
|
renderMenu,
|
||||||
mobileClassName,
|
mobileClassName,
|
||||||
virtualThreshold = 200,
|
virtualThreshold = 100,
|
||||||
useMobileUI = false
|
useMobileUI = false
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const {selection} = this.state;
|
const {selection} = this.state;
|
||||||
@ -960,7 +963,8 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||||||
})
|
})
|
||||||
: options.concat()
|
: options.concat()
|
||||||
).filter((option: Option) => !option.hidden && option.visible !== false);
|
).filter((option: Option) => !option.hidden && option.visible !== false);
|
||||||
|
const enableVirtualRender =
|
||||||
|
filtedOptions.length && filtedOptions.length > virtualThreshold;
|
||||||
const selectionValues = selection.map(select => select[valueField]);
|
const selectionValues = selection.map(select => select[valueField]);
|
||||||
if (multiple && checkAll) {
|
if (multiple && checkAll) {
|
||||||
const optionsValues = (checkAllBySearch ? filtedOptions : options).map(
|
const optionsValues = (checkAllBySearch ? filtedOptions : options).map(
|
||||||
@ -1000,7 +1004,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||||||
item,
|
item,
|
||||||
disabled: item.disabled
|
disabled: item.disabled
|
||||||
})}
|
})}
|
||||||
style={style}
|
style={merge(style, enableVirtualRender ? {width: '100%'} : {})}
|
||||||
className={cx(`Select-option`, {
|
className={cx(`Select-option`, {
|
||||||
'is-disabled': item.disabled,
|
'is-disabled': item.disabled,
|
||||||
'is-highlight': highlightedIndex === index,
|
'is-highlight': highlightedIndex === index,
|
||||||
@ -1107,8 +1111,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||||||
<div
|
<div
|
||||||
ref={this.menu}
|
ref={this.menu}
|
||||||
className={cx('Select-menu', {
|
className={cx('Select-menu', {
|
||||||
'Select--longlist':
|
'Select--longlist': enableVirtualRender,
|
||||||
filtedOptions.length && filtedOptions.length > virtualThreshold,
|
|
||||||
'is-mobile': mobileUI
|
'is-mobile': mobileUI
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
@ -1654,7 +1654,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
<div
|
<div
|
||||||
class="cxd-PopOver cxd-Select-popover cxd-PopOver--leftBottomLeftTop"
|
class="cxd-PopOver cxd-Select-popover cxd-PopOver--leftBottomLeftTop"
|
||||||
style="display: block; width: 0px; left: 0px; top: 0px; position: relative;"
|
style="display: block; width: auto; left: 0px; top: 0px; position: relative;"
|
||||||
theme="cxd"
|
theme="cxd"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1674,14 +1674,14 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
style="overflow: auto; will-change: transform; height: 266px; width: 100%;"
|
style="overflow: auto; will-change: transform; height: 266px; width: 100%;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style="position: relative; width: auto; white-space: nowrap; min-height: 100%; height: 7000px;"
|
style="position: relative; width: auto; white-space: nowrap; min-height: 100%; height: 6400px;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-selected="false"
|
aria-selected="false"
|
||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-0"
|
id="downshift-1-item-0"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 0px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 0px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1695,7 +1695,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-1"
|
id="downshift-1-item-1"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 35px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 32px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1709,7 +1709,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-2"
|
id="downshift-1-item-2"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 70px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 64px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1723,7 +1723,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-3"
|
id="downshift-1-item-3"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 105px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 96px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1737,7 +1737,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-4"
|
id="downshift-1-item-4"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 140px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 128px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1751,7 +1751,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-5"
|
id="downshift-1-item-5"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 175px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 160px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1765,7 +1765,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-6"
|
id="downshift-1-item-6"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 210px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 192px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1779,7 +1779,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-7"
|
id="downshift-1-item-7"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 245px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 224px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1793,7 +1793,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-8"
|
id="downshift-1-item-8"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 280px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 256px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1807,7 +1807,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-9"
|
id="downshift-1-item-9"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 315px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 288px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1821,7 +1821,7 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
class="cxd-Select-option"
|
class="cxd-Select-option"
|
||||||
id="downshift-1-item-10"
|
id="downshift-1-item-10"
|
||||||
role="option"
|
role="option"
|
||||||
style="position: absolute; top: 350px; left: 0px; width: auto; height: 35px;"
|
style="position: absolute; top: 320px; left: 0px; width: 100%; height: 32px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="cxd-Select-option-content"
|
class="cxd-Select-option-content"
|
||||||
@ -1830,6 +1830,20 @@ exports[`Renderer:select virtual 1`] = `
|
|||||||
option10
|
option10
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
aria-selected="false"
|
||||||
|
class="cxd-Select-option"
|
||||||
|
id="downshift-1-item-11"
|
||||||
|
role="option"
|
||||||
|
style="position: absolute; top: 352px; left: 0px; width: 100%; height: 32px;"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="cxd-Select-option-content"
|
||||||
|
title="option11"
|
||||||
|
>
|
||||||
|
option11
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user