输入类 · Select
选择器
用户可以通过 Select 选择器从一个选项集合中去选中一个或多个选项,并呈现最终选择结果

代码演示

如何引入

注意
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方式传入)
注意
1. OptGroup必须为Select的直接子元素,不允许有Fragment或DIV等其他元素阻隔
2. 若Select的children需要动态更新,OptGroup上的key也需要进行更新,否则Select无法识别

不同尺寸

通过Size控制选择器的大小尺寸: small / default / large

不同校验状态样式

validateStatus: default / warning / error
仅影响背景颜色等样式表现

配置前缀、后缀、清除按钮

  • 可以通过prefix传入选择框前缀,通过suffix传入选择框后缀,可以为文本或者 ReactNode
    当 prefix、suffix 传入的内容为文本或者 Icon 时,会自动带上左右间隔,若为自定义 ReactNode,则左右间隔为 0
  • 通过showClear控制清除按钮是否展示
  • 通过showArrow控制右侧下拉箭头是否展示

内嵌标签

通过设置insetLabel,你可以给 Select 设置 label,可以传入 string 或者 ReactNode
当传入类型为 ReactNode 时,注意要自行处理 label 与文本之间的间隔

在顶部/底部渲染附加项

我们在弹出层顶部、底部分别预留了插槽,当你需要在弹出层中添加自定义 node 时
可以通过innerBottomSlot或者outerBottomSlot传入,自定义 node 将会被渲染在弹出层底部;可以通过innerTopSlot或者outerTopSlot传入,自定义 node 将会被渲染在弹出层顶部。
  • innerTopSlotinnerBottomSlot将会被渲染在 optionList 内部,当滚动到 optionList 顶部/底部时展现
  • outerTopSlotouterBottomSlot将会被渲染为与 optionList 平级,无论 optionList 是否滚动,都会始终展现
通过 outerTopSlot 将内容插入顶部插槽

受控组件

传入 value 时 Select 为受控组件,所选中的值完全由 value 决定。

动态修改 Options

如果需要动态更新 Options,应该使用受控的 value

联动

使用受控value,实现不同Select之间的联动。如果是带有层级关系的复杂联动建议直接使用Cascader组件

开启搜索

filter 置为 true,开启搜索能力。默认搜索策略将为 input 输入值与 option 的 label 值进行 include 对比
默认情况下,多选选中后会自动清空搜索关键字。若你希望保留,可以通过 autoClearSearchValue 设为 false 关闭默认行为(v2.3后提供)

远程搜索

带有远程搜索,防抖请求,加载状态的多选示例
通过filter开启搜索能力
remote设置为 true 关闭对当前数据的筛选过滤(在 v0.24.0 后提供)
通过动态更新optionList更新下拉菜单中的备选项
使用受控的 value 属性

自定义搜索逻辑

可以将 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

获取选项的其他属性

默认情况下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时开启列表虚拟化,用于大量 Option 节点的情况优化性能
virtualize 是一个包含下列值的对象:
  • height: Option 列表高度值,默认 300
  • width: Option 列表宽度值,默认 100%
  • itemSize: 每行 Option 的高度,必传

自定义触发器

如果 Select 默认的触发器样式满足不了你的需求,可以用triggerRender自定义选择框的展示
triggerRender 入参如下

自定义候选项渲染

  • 简单的自定义:通过Option的label属性或者children传入ReactNode,你可以控制候选项的渲染,此时内容会自动带上内边距、背景色等样式
  • 完全自定义:通过传入renderOptionItem,你可以完全接管列表中候选项的渲染,并且从回调入参中,获取到相关的状态值。实现更高自由度的结构渲染
    注意事项:
    1. props传入的style需在wrapper dom上进行消费,否则在虚拟化场景下会无法正常使用
    2. 选中(selected)、聚焦(focused)、禁用(disabled)等状态的样式需自行加上,你可以从props中获取到相对的boolean值
    3. onMouseEnter需在wrapper dom上绑定,否则上下键盘操作时显示会有问题
    4. 如果你的自定义 item 为 Select.Option,需要将 renderProps.onClick 透传给 Option 的 onSelect prop

API 参考

Select Props

属性说明类型默认值
allowCreate是否允许用户创建新条目,需配合 filter 使用booleanfalse
arrowIcon自定义右侧下拉箭头Icon,当showClear开关打开且当前有选中值时,hover会优先显示clear icon
v1.15.0 后提供
ReactNode
autoAdjustOverflow浮层被遮挡时是否自动调整方向(暂时仅支持竖直方向,且插入的父级为 body)booleantrue
autoClearSearchValue选中选项后,是否自动清空搜索关键字,当mutilple、filter都开启时生效
v2.3.0 后提供
booleantrue
autoFocus初始渲染时是否自动 focusbooleanfalse
className类名string
clickToHide已展开时,点击选择框是否自动收起下拉列表booleanfalse
defaultValue初始选中的值string|number|array
defaultOpen是否默认展开下拉列表booleanfalse
disabled是否禁用booleanfalse
defaultActiveFirstOption是否默认高亮第一个选项(按回车可直接选中)booleanfalse
dropdownClassName弹出层的 classNamestring
dropdownMatchSelectWidth下拉菜单最小宽度是否等于 Selectbooleantrue
dropdownStyle弹出层的样式object
emptyContent无结果时展示的内容。设为 null 时,下拉列表将不展示string|ReactNode
filter是否可搜索,默认为 false。传入 true 时,代表开启搜索并采用默认过滤策略(label 是否与 sugInput 匹配),传入值为函数时,会接收 sugInput, option 两个参数,当 option 符合筛选条件应返回 true,否则返回 falseboolean |function(sugInput, option)false
getPopupContainer指定父级 DOM,弹层将会渲染至该 DOM 中,自定义需要设置 position: relativefunction():HTMLElement() => document.body
inputPropsfilter为true时, input输入框的额外配置参数,具体可配置属性请参考Input组件(注意:请不要传入value、ref、onChange、onFocus,否则会覆盖Select相关回调,影响组件行为)
v2.2.0 后提供
object
innerTopSlot渲染在弹出层顶部,在 optionList 内部的自定义 slotReactNode
innerBottomSlot渲染在弹出层底部,在 optionList 内部的自定义 slotReactNode
insetLabel同上,与 prefix 区别是 fontWeight 更大ReactNode
loading下拉列表是否展示加载动画booleanfalse
maxTagCount多选模式下,已选项超出 maxTagCount 时,后续选项会被渲染成+N 的形式number
max最多可选几项,仅在多选模式下生效number
maxHeight下拉菜单中 optionList 的最大高度string|number300
multiple是否多选booleanfalse
outerTopSlot渲染在弹出层顶部,与 optionList 平级的自定义 slotReactNode
outerBottomSlot渲染在弹出层底部,与 optionList 平级的自定义 slotReactNode
onBlur失去焦点时的回调function(event)
onChange变化时回调函数function(value:string|number|array)
onCreateallowCreate 为 true,创建备选项时的回调function(option)
onClear清除按钮的回调function
onChangeWithObject是否将选中项 option 的其他属性作为回调。设为 true 时,onChange 的入参类型会从 string 变为 object: { value, label, ...rest }booleanfalse
onDropdownVisibleChange下拉菜单展开/收起时的回调function(visible:boolean)
onListScroll候选项列表滚动时的回调function(e)
onSearchinput 输入框内容发生改变时回调函数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 positionstring'bottomLeft'
prefix选择框的前缀标签ReactNode
renderCreateItemallowCreate 为 true 时,可自定义创建标签的渲染function(inputValue:string)inputValue => '创建' + inputValue
renderSelectedItem通过 renderSelectedItem 自定义选择框中已选项标签的渲染function(option)
renderOptionItem通过 renderOptionItem 完全自定义下拉列表中候选项的渲染function(props) 入参详见Demo
remote是否开启远程搜索,当 remote 为 true 时,input 内容改变后不会进行本地筛选匹配booleanfalse
size大小,可选值 default/small/largestring'default'
style样式object
suffix选择框的后缀标签ReactNode
showClear是否展示清除按钮booleanfalse
showArrow是否展示下拉箭头booleantrue
spacing浮层与选择器的距离number4
triggerRender自定义触发器渲染function
value当前选中的的值,传入该值时将作为受控组件,配合 onChange 使用string|number|array
validateStatus校验结果,可选warningerrordefault(只影响样式背景色)string'default'
virtualize列表虚拟化,用于大量节点的情况优化性能表现,由 height, width, itemSize 组成object
zIndex弹层的 zIndexnumber1030

Option Props


不同 Option 的 label 必须唯一,不允许重复
属性说明类型默认值
className样式类名string
disabled是否禁用booleanfalse
label展示的文本。渲染时优先取 label,若无则取 children、value,依次降级string|ReactNode
showTick被选中时,展示 √ 的 Iconbooleantrue
style样式object
value属性值string|number

OptGroup Props


属性说明类型版本
className样式类名stringv0.31.0
label展示的文本ReactNodev0.31.0
style样式objectv0.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调用时可以选中所有Optionv1.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的名称。

© 2021 Semi Design. All rights reserved.

京ICP备19058139号-13浙公网安备 33011002016131号

Designed & Developed with love by Douyin FE & MED