代码演示
如何引入
注意
Select的直接子元素必须为 Option 或者 OptGroup,不允许为其他Element
基本使用
每个 Option 标签都必须声明 value 属性,Option 的 children 或 label 将会被渲染至下拉列表中
以数组形式传入 Option
可以直接通过
optionList
传入一个对象数组,每个对象必须包含 value/label 属性(当然其他属性也可以通过此方式传入)多选
配置
multiple
属性,可以支持多选配置
maxTagCount
可以限制已选项展示的数量,超出部分将以+N 的方式展示配置
max
属性可限制最大可选的数量,超出最大限制数量后无法选中,同时会触发onExceed
回调分组
分组功能 v0.31.0 后提供
用 OptGroup 进行分组(分组功能仅支持通过jsx方式声明children使用,不支持optionList方式传入)
用 OptGroup 进行分组(分组功能仅支持通过jsx方式声明children使用,不支持optionList方式传入)
注意
1. OptGroup必须为Select的直接子元素,不允许有Fragment或DIV等其他元素阻隔
2. 若Select的children需要动态更新,OptGroup上的key也需要进行更新,否则Select无法识别
2. 若Select的children需要动态更新,OptGroup上的key也需要进行更新,否则Select无法识别
不同尺寸
通过Size控制选择器的大小尺寸:
small
/ default
/ large
不同校验状态样式
validateStatus: default / warning / error
仅影响背景颜色等样式表现
仅影响背景颜色等样式表现
配置前缀、后缀、清除按钮
- 可以通过
prefix
传入选择框前缀,通过suffix
传入选择框后缀,可以为文本或者 ReactNode
当 prefix、suffix 传入的内容为文本或者 Icon 时,会自动带上左右间隔,若为自定义 ReactNode,则左右间隔为 0 - 通过
showClear
控制清除按钮是否展示 - 通过
showArrow
控制右侧下拉箭头是否展示
内嵌标签
通过设置
当传入类型为 ReactNode 时,注意要自行处理 label 与文本之间的间隔
insetLabel
,你可以给 Select 设置 label,可以传入 string 或者 ReactNode当传入类型为 ReactNode 时,注意要自行处理 label 与文本之间的间隔
在顶部/底部渲染附加项
我们在弹出层顶部、底部分别预留了插槽,当你需要在弹出层中添加自定义 node 时
可以通过
可以通过
innerBottomSlot
或者outerBottomSlot
传入,自定义 node 将会被渲染在弹出层底部;可以通过innerTopSlot
或者outerTopSlot
传入,自定义 node 将会被渲染在弹出层顶部。innerTopSlot
和innerBottomSlot
将会被渲染在 optionList 内部,当滚动到 optionList 顶部/底部时展现outerTopSlot
和outerBottomSlot
将会被渲染为与 optionList 平级,无论 optionList 是否滚动,都会始终展现
通过 outerTopSlot 将内容插入顶部插槽
受控组件
传入 value 时 Select 为受控组件,所选中的值完全由 value 决定。
动态修改 Options
如果需要动态更新 Options,应该使用受控的 value
联动
使用受控value,实现不同Select之间的联动。如果是带有层级关系的复杂联动建议直接使用
Cascader
组件开启搜索
将
默认情况下,多选选中后会自动清空搜索关键字。若你希望保留,可以通过 autoClearSearchValue 设为 false 关闭默认行为(v2.3后提供)
filter
置为 true,开启搜索能力。默认搜索策略将为 input 输入值与 option 的 label 值进行 include 对比默认情况下,多选选中后会自动清空搜索关键字。若你希望保留,可以通过 autoClearSearchValue 设为 false 关闭默认行为(v2.3后提供)
远程搜索
带有远程搜索,防抖请求,加载状态的多选示例
通过
将
通过动态更新
使用受控的 value 属性
通过
filter
开启搜索能力将
remote
设置为 true 关闭对当前数据的筛选过滤(在 v0.24.0 后提供)通过动态更新
optionList
更新下拉菜单中的备选项使用受控的 value 属性
自定义搜索逻辑
可以将
如下例子,选项 label 值都是大写,默认的检索策略是字符串 include 对比,会区分大小写。
通过传入自定义
filter
置为自定义函数,定制你想要的搜索策略如下例子,选项 label 值都是大写,默认的检索策略是字符串 include 对比,会区分大小写。
通过传入自定义
filter
函数,检索时输入小写字母也能搜到相应内容。自定义已选项标签渲染
默认情况下,选中选项后会将 option.label 或 option.children 的内容回填到选择框中
但你可以通过
但你可以通过
renderSelectedItem
自定义选择框中已选项标签的渲染结构- 单选时
renderSelectedItem(optionNode:object) => content:ReactNode
- 多选时
renderSelectedItem(optionNode:object, { index:number, onClose:function }) => { isRenderInTag:bool, content:ReactNode }
- isRenderInTag 为 true 时,会自动将 content 包裹在 Tag 中渲染(带有背景色以及关闭按钮)
- isRenderInTag 为 false 时,将直接渲染返回的 content
自定义弹出层样式
你可以通过 dropdownClassName、dropdownStyle 控制弹出层的样式
例如当自定义弹出层的宽度时,可以通过 dropdownStyle 传入 width
例如当自定义弹出层的宽度时,可以通过 dropdownStyle 传入 width
获取选项的其他属性
默认情况下
此时
onChange
只能拿到 value,如果需要拿选中节点的其他属性,可以使用onChangeWithObject
属性此时
onChange
函数的入参将会是 object,包含 option 的各种属性,例如 onChange({ value, label, ...rest })
注意
当 onChangeWithObject 置为 true 时,`defaultValue`/`Value`也应为 object,且须带有`value`、`label` key
创建条目
设置
允许通过
可以配合
allowCreate
,可以创建并选中选项中不存在的条目允许通过
renderCreateItem
自定义创建标签时的内容显示(通过返回 ReactNode,注意你需要自定义样式),该函数默认值为 (input) => '创建' + input可以配合
defaultActiveFirstOption
属性使用,自动选中第一项,当输入完内容直接回车时,可立即创建 注意
当开启allowCreate后,不会再响应对Children或者optionList的更新
虚拟化
传入
virtualize 是一个包含下列值的对象:
virtualize
时开启列表虚拟化,用于大量 Option 节点的情况优化性能virtualize 是一个包含下列值的对象:
- height: Option 列表高度值,默认 300
- width: Option 列表宽度值,默认 100%
- itemSize: 每行 Option 的高度,必传
自定义触发器
如果 Select 默认的触发器样式满足不了你的需求,可以用
triggerRender
自定义选择框的展示triggerRender 入参如下
自定义候选项渲染
- 简单的自定义:通过Option的label属性或者children传入ReactNode,你可以控制候选项的渲染,此时内容会自动带上内边距、背景色等样式
- 完全自定义:通过传入
renderOptionItem
,你可以完全接管列表中候选项的渲染,并且从回调入参中,获取到相关的状态值。实现更高自由度的结构渲染
注意事项:- props传入的style需在wrapper dom上进行消费,否则在虚拟化场景下会无法正常使用
- 选中(selected)、聚焦(focused)、禁用(disabled)等状态的样式需自行加上,你可以从props中获取到相对的boolean值
- onMouseEnter需在wrapper dom上绑定,否则上下键盘操作时显示会有问题
- 如果你的自定义 item 为 Select.Option,需要将 renderProps.onClick 透传给 Option 的 onSelect prop
API 参考
Select Props
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
allowCreate | 是否允许用户创建新条目,需配合 filter 使用 | boolean | false |
arrowIcon | 自定义右侧下拉箭头Icon,当showClear开关打开且当前有选中值时,hover会优先显示clear icon v1.15.0 后提供 | ReactNode | |
autoAdjustOverflow | 浮层被遮挡时是否自动调整方向(暂时仅支持竖直方向,且插入的父级为 body) | boolean | true |
autoClearSearchValue | 选中选项后,是否自动清空搜索关键字,当mutilple、filter都开启时生效 v2.3.0 后提供 | boolean | true |
autoFocus | 初始渲染时是否自动 focus | boolean | false |
className | 类名 | string | |
clickToHide | 已展开时,点击选择框是否自动收起下拉列表 | boolean | false |
defaultValue | 初始选中的值 | string|number|array | |
defaultOpen | 是否默认展开下拉列表 | boolean | false |
disabled | 是否禁用 | boolean | false |
defaultActiveFirstOption | 是否默认高亮第一个选项(按回车可直接选中) | boolean | false |
dropdownClassName | 弹出层的 className | string | |
dropdownMatchSelectWidth | 下拉菜单最小宽度是否等于 Select | boolean | true |
dropdownStyle | 弹出层的样式 | object | |
emptyContent | 无结果时展示的内容。设为 null 时,下拉列表将不展示 | string|ReactNode | |
filter | 是否可搜索,默认为 false。传入 true 时,代表开启搜索并采用默认过滤策略(label 是否与 sugInput 匹配),传入值为函数时,会接收 sugInput, option 两个参数,当 option 符合筛选条件应返回 true,否则返回 false | boolean |function(sugInput, option) | false |
getPopupContainer | 指定父级 DOM,弹层将会渲染至该 DOM 中,自定义需要设置 position: relative | function():HTMLElement | () => document.body |
inputProps | filter为true时, input输入框的额外配置参数,具体可配置属性请参考Input组件(注意:请不要传入value、ref、onChange、onFocus,否则会覆盖Select相关回调,影响组件行为) v2.2.0 后提供 | object | |
innerTopSlot | 渲染在弹出层顶部,在 optionList 内部的自定义 slot | ReactNode | |
innerBottomSlot | 渲染在弹出层底部,在 optionList 内部的自定义 slot | ReactNode | |
insetLabel | 同上,与 prefix 区别是 fontWeight 更大 | ReactNode | |
loading | 下拉列表是否展示加载动画 | boolean | false |
maxTagCount | 多选模式下,已选项超出 maxTagCount 时,后续选项会被渲染成+N 的形式 | number | |
max | 最多可选几项,仅在多选模式下生效 | number | |
maxHeight | 下拉菜单中 optionList 的最大高度 | string|number | 300 |
multiple | 是否多选 | boolean | false |
outerTopSlot | 渲染在弹出层顶部,与 optionList 平级的自定义 slot | ReactNode | |
outerBottomSlot | 渲染在弹出层底部,与 optionList 平级的自定义 slot | ReactNode | |
onBlur | 失去焦点时的回调 | function(event) | |
onChange | 变化时回调函数 | function(value:string|number|array) | |
onCreate | allowCreate 为 true,创建备选项时的回调 | function(option) | |
onClear | 清除按钮的回调 | function | |
onChangeWithObject | 是否将选中项 option 的其他属性作为回调。设为 true 时,onChange 的入参类型会从 string 变为 object: { value, label, ...rest } | boolean | false |
onDropdownVisibleChange | 下拉菜单展开/收起时的回调 | function(visible:boolean) | |
onListScroll | 候选项列表滚动时的回调 | function(e) | |
onSearch | input 输入框内容发生改变时回调函数 | function(sugInput:string) | |
onSelect | 被选中时的回调 | function(value, option) | |
onDeselect | 取消选中时的回调,仅在多选时有效 | function(value, option) | |
onExceed | 当试图选择数超出 max 限制时的回调,仅在多选时生效 入参在v1.16.0后提供 | function(option) | |
onFocus | 获得焦点时的回调 | function(event) | |
optionList | 可以通过该属性传入 Option,请确保数组内每个元素都具备 label、value 属性 | array([{value, label}]) | |
placeholder | 选择框默认文字 | ReactNode | |
position | 菜单展开的位置,可选项同Tooltip position | string | 'bottomLeft' |
prefix | 选择框的前缀标签 | ReactNode | |
renderCreateItem | allowCreate 为 true 时,可自定义创建标签的渲染 | function(inputValue:string) | inputValue => '创建' + inputValue |
renderSelectedItem | 通过 renderSelectedItem 自定义选择框中已选项标签的渲染 | function(option) | |
renderOptionItem | 通过 renderOptionItem 完全自定义下拉列表中候选项的渲染 | function(props) 入参详见Demo | |
remote | 是否开启远程搜索,当 remote 为 true 时,input 内容改变后不会进行本地筛选匹配 | boolean | false |
size | 大小,可选值 default /small /large | string | 'default' |
style | 样式 | object | |
suffix | 选择框的后缀标签 | ReactNode | |
showClear | 是否展示清除按钮 | boolean | false |
showArrow | 是否展示下拉箭头 | boolean | true |
spacing | 浮层与选择器的距离 | number | 4 |
triggerRender | 自定义触发器渲染 | function | |
value | 当前选中的的值,传入该值时将作为受控组件,配合 onChange 使用 | string|number|array | |
validateStatus | 校验结果,可选warning 、error 、 default (只影响样式背景色) | string | 'default' |
virtualize | 列表虚拟化,用于大量节点的情况优化性能表现,由 height, width, itemSize 组成 | object | |
zIndex | 弹层的 zIndex | number | 1030 |
Option Props
不同 Option 的 label 必须唯一,不允许重复
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
className | 样式类名 | string | |
disabled | 是否禁用 | boolean | false |
label | 展示的文本。渲染时优先取 label,若无则取 children、value,依次降级 | string|ReactNode | |
showTick | 被选中时,展示 √ 的 Icon | boolean | true |
style | 样式 | object | |
value | 属性值 | string|number |
OptGroup Props
属性 | 说明 | 类型 | 版本 |
---|---|---|---|
className | 样式类名 | string | v0.31.0 |
label | 展示的文本 | ReactNode | v0.31.0 |
style | 样式 | object | v0.31.0 |
Method()
绑定在ref上的方法,可以通过ref调用实现某些特殊交互
方法 | 说明 | 版本 |
---|---|---|
close | 调用时可以手动关闭下拉列表 | v0.34.0 |
open | 调用时可以手动展开下拉列表 | v0.34.0 |
focus | 调用时可以手动聚焦 | v1.11.0 |
clearInput | 调用时可以手动清空input搜索框的值 | v1.18.0 |
deselectAll | 调用时可以手动清空所有已选项 | v1.18.0 |
selectAll | 调用时可以选中所有Option | v1.18.0 |
Accessibility
ARIA
- Select trigger 的 role 为 combobox,弹出层的 role 为 listbox,可选项的 role 为 option
- Select trigger 具有 aria-haspopup、aria-expanded、aria-controls 属性,表示 trigger 与弹出层的关系
- 多选时,listbox aria-multiselectable 为 true,表示当前可以多选
- Option 选中时,aria-selected 为 true;当 Option 禁用时,aria-disabled 为 true
设计变量
FAQ
- 可搜索的 Select,使用远程数据动态更新
optionList
,为什么在异步请求完成之前有时候会出现暂无数据?
请检查是否设置了remote={true}
,不设置 remote 的情况下,默认会将 input 框输入值与当前的 optionList 进行一次对比筛选,如果无匹配时,就会显示暂无数据。
可以通过设置 remote 为 true 关闭对本地当前数据的匹配筛选。 - 使用jsx方式声明Option,label为i18n后的内容,切换locale后未能重新渲染
- children jsx方式声明Options时,由于是ReactNode,不可能用deepEqual来做对比判断内容是否有更新(性能消耗过大),所以会收集children ReactNode的key,当key不变时,就认为Options都没有发生变化,不会走重新收集数据的流程。你可以将locale也作为Option key的一部分。
- 使用optionList方式传入,也可以解决问题。因为对于object形式传入,key相对有限,Select内部会使用isEqual来判断是否发生变化
- 使用jsx方式声明Option,动态切换disabled属性后未能重新渲染
- 原因同上,你可以重新给Option设定不同的key值,或者使用optionList方式声明候选项
- Select会自动限制下拉菜单的宽度吗?
- 会给minWidth,但不会写死width。如果有需要的话,可以自己通过dropdownStyle来添加。
- 设置allowCreate后,动态更新optionList或者children不生效
- allowCreate主要用于本地创建的场景,开启该项后,相当于强接管了optionList / children,不会再响应外部对这两类值的更新。
- 为什么Semi的Select要求label必须唯一,而不是value必须唯一?
- 首先,我们一定需要一个唯一标识符用来做选中的判断。几乎所有UI库,对Select.Option使用时,最低要求都只会要求传入label、value两个值,而不会再单独要求传入一个key(过于繁琐)。Semi延续了这个设定
- 那么为什么在semi的select中是label而不是value呢?
- option的label是用户感知的内容。从交互的角度而言,如果出现两个展示上一模一样的选项,对用户感知而言,他们看上去是一样的,无法进行区分,但选中的作用又不一样(例如一个value为0,另一个为1),是不合理的。(用户第一反应往往是重复了,可能出bug了)
- label唯一、value重复,在日常使用中会更为常见。例如,一个根据app名称选择公司id的选择器,value是app对应的公司id,label是app的名称。