2021SC@SDUSC
Select选择器
用法:
- 弹出一个下拉菜单给用户选择操作,用于代替原生的选择器,或者需要一个更优雅的多选器时。
- 当选项少时(少于 5 项),建议直接将选项平铺,使用 Radio 是更好的选择。
API
<Select>
<Option value="lucy">lucy</Option>
</Select>
Select
参数 | 说明 | 类型 | 默认值 | 版本 |
---|---|---|---|---|
allowClear | 支持清除 | boolean | false | |
autoClearSearchValue | 是否在选中项后清空搜索框,只在 mode 为 multiple 或 tags 时有效 | boolean | true | |
autoFocus | 默认获取焦点 | boolean | false | |
bordered | 是否有边框 | boolean | true | |
clearIcon | 自定义的多选框清空图标 | ReactNode | - | |
defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
defaultValue | 指定默认选中的条目 | string | string[] number | number[] LabeledValue | LabeledValue[] | - | |
disabled | 是否禁用 | boolean | false | |
dropdownClassName | 下拉菜单的 className 属性 | string | - | |
dropdownMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 min-width ,当值小于选择框宽度时会被忽略。false 时会关闭虚拟滚动 | boolean | number | true | |
dropdownRender | 自定义下拉框内容 | (originNode: ReactNode) => ReactNode | - | |
dropdownStyle | 下拉菜单的 style 属性 | CSSProperties | - | |
fieldNames | 自定义节点 label、key、options 的字段 | object | { label: label , key: key , options: options } | 4.17.0 |
filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false | boolean | function(inputValue, option) | true | |
filterSort | 搜索时对筛选结果项的排序函数, 类似Array.sort 里的 compareFunction | (optionA: Option, optionB: Option) => number | - | 4.9.0 |
getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | function(triggerNode) | () => document.body | |
labelInValue | 是否把每个选项的 label 包装到 value 中,会把 Select 的 value 类型从 string 变为 { value: string, label: ReactNode } 的格式 | boolean | false | |
listHeight | 设置弹窗滚动高度 | number | 256 | |
loading | 加载中状态 | boolean | false | |
maxTagCount | 最多显示多少个 tag,响应式模式会对性能产生损耗 | number | responsive | - | responsive: 4.10 |
maxTagPlaceholder | 隐藏 tag 时显示的内容 | ReactNode | function(omittedValues) | - | |
maxTagTextLength | 最大显示的 tag 文本长度 | number | - | |
menuItemSelectedIcon | 自定义多选时当前选中的条目图标 | ReactNode | - | |
mode | 设置 Select 的模式为多选或标签 | multiple | tags | - | |
notFoundContent | 当下拉列表为空时显示的内容 | ReactNode | Not Found | |
open | 是否展开下拉菜单 | boolean | - | |
optionFilterProp | 搜索时过滤对应的 option 属性,如设置为 children 表示对内嵌内容进行搜索。若通过 options 属性配置选项内容,建议设置 optionFilterProp="label" 来对内容进行搜索。 | string | value | |
optionLabelProp | 回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 value 。 | string | children | |
options | 数据化配置选项内容,相比 jsx 定义会获得更好的渲染性能 | { label, value }[] | - | |
placeholder | 选择框默认文本 | string | - | |
removeIcon | 自定义的多选框清除图标 | ReactNode | - | |
searchValue | 控制搜索文本 | string | - | |
showArrow | 是否显示下拉小箭头 | boolean | 单选为 true,多选为 false | |
showSearch | 使单选模式可搜索 | boolean | false | |
size | 选择框大小 | large | middle | small | middle | |
suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | |
tagRender | 自定义 tag 内容 render,仅在 mode 为 multiple 或 tags 时生效 | (props) => ReactNode | - | |
tokenSeparators | 在 tags 和 multiple 模式下自动分词的分隔符 | string[] | - | |
value | 指定当前选中的条目,多选时为一个数组。(value 数组引用未变化时,Select 不会更新) | string | string[] number | number[] LabeledValue | LabeledValue[] | - | |
virtual | 设置 false 时关闭虚拟滚动 | boolean | true | 4.1.0 |
onBlur | 失去焦点时回调 | function | - | |
onChange | 选中 option,或 input 的 value 变化时,调用此函数 | function(value, option:Option | Array<Option>) | - | |
onClear | 清除内容时回调 | function | - | 4.6.0 |
onDeselect | 取消选中时调用,参数为选中项的 value (或 key) 值,仅在 multiple 或 tags 模式下生效 | function(string | number | LabeledValue) | - | |
onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - | |
onFocus | 获得焦点时回调 | function | - | |
onInputKeyDown | 按键按下时回调 | function | - | |
onMouseEnter | 鼠标移入时回调 | function | - | |
onMouseLeave | 鼠标移出时回调 | function | - | |
onPopupScroll | 下拉列表滚动时的回调 | function | - | |
onSearch | 文本框值变化时回调 | function(value: string) | - | |
onSelect | 被选中时调用,参数为选中项的 value (或 key) 值 | function(string | number | LabeledValue, option: Option) | - |
Option props
参数 | 说明 | 类型 | 默认值 | 版本 |
---|---|---|---|---|
className | Option 器类名 | string | - | |
disabled | 是否禁用 | boolean | false | |
title | 选中该 Option 后,Select 的 title | string | - | |
value | 默认根据此属性值进行筛选 | string | number | - |
OptGroup props
参数 | 说明 | 类型 | 默认值 | 版本 |
---|---|---|---|---|
key | Key | string | - | |
label | 组名 | string | React.Element | - |
部分源码
import * as React from 'react';
import omit from 'rc-util/lib/omit';
import classNames from 'classnames';
import RcSelect, { Option, OptGroup, SelectProps as RcSelectProps } from 'rc-select';
import { OptionProps } from 'rc-select/lib/Option';
import { ConfigContext } from '../config-provider';
import getIcons from './utils/iconUtil';
import SizeContext, { SizeType } from '../config-provider/SizeContext';
import { getTransitionName } from '../_util/motion';
import部分可以看到rc-select,可以见得ant-design中的select是基于react的select实现的。
type RawValue = string | number;
export { OptionProps };
export type OptionType = typeof Option;
export interface LabeledValue {
key?: string;
value: RawValue;
label: React.ReactNode;
}
export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[] | undefined;
RawValue原始值采用字符串或数字的联合类型
接口LabeledValue则是简单的key value外加一个label的格式
SelectValue能够选用RawValue或是LabeledValue
export interface InternalSelectProps<VT> extends Omit<RcSelectProps<VT>, 'mode'> {
suffixIcon?: React.ReactNode;
size?: SizeType;
mode?: 'multiple' | 'tags' | 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
bordered?: boolean;
}
export interface SelectProps<VT>
extends Omit<
InternalSelectProps<VT>,
'inputIcon' | 'mode' | 'getInputElement' | 'getRawInputElement' | 'backfill'
> {
mode?: 'multiple' | 'tags';
}
export interface RefSelectProps {
focus: () => void;
blur: () => void;
}
COMBOBOX_MODE下拉框模式
这里给出了SelectProps的接口
const InternalSelect = <VT extends SelectValue = SelectValue>(
{
prefixCls: customizePrefixCls,
bordered = true,
className,
getPopupContainer,
dropdownClassName,
listHeight = 256,
listItemHeight = 24,
size: customizeSize,
notFoundContent,
...props
}: SelectProps<VT>,
ref: React.Ref<RefSelectProps>,
) => {
const {
getPopupContainer: getContextPopupContainer,
getPrefixCls,
renderEmpty,
direction,
virtual,
dropdownMatchSelectWidth,
} = React.useContext(ConfigContext);
const size = React.useContext(SizeContext);
const prefixCls = getPrefixCls('select', customizePrefixCls);
const rootPrefixCls = getPrefixCls();
const mode = React.useMemo(() => {
const { mode: m } = props as InternalSelectProps<VT>;
if ((m as any) === 'combobox') {
return undefined;
}
if (m === SECRET_COMBOBOX_MODE_DO_NOT_USE) {
return 'combobox';
}
return m;
}, [props.mode]);
const isMultiple = mode === 'multiple' || mode === 'tags';
// ===================== Empty =====================
let mergedNotFound: React.ReactNode;
if (notFoundContent !== undefined) {
mergedNotFound = notFoundContent;
} else if (mode === 'combobox') {
mergedNotFound = null;
} else {
mergedNotFound = renderEmpty('Select');
}
// ===================== Icons =====================
const { suffixIcon, itemIcon, removeIcon, clearIcon } = getIcons({
...props,
multiple: isMultiple,
prefixCls,
});
const selectProps = omit(props as typeof props & { itemIcon: any }, ['suffixIcon', 'itemIcon']);
const rcSelectRtlDropDownClassName = classNames(dropdownClassName, {
[`${prefixCls}-dropdown-${direction}`]: direction === 'rtl',
});
const mergedSize = customizeSize || size;
const mergedClassName = classNames(
{
[`${prefixCls}-lg`]: mergedSize === 'large',
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-borderless`]: !bordered,
},
className,
);
return (
<RcSelect<VT>
ref={ref as any}
virtual={virtual}
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
{...selectProps}
transitionName={getTransitionName(rootPrefixCls, 'slide-up', props.transitionName)}
listHeight={listHeight}
listItemHeight={listItemHeight}
mode={mode}
prefixCls={prefixCls}
direction={direction}
inputIcon={suffixIcon}
menuItemSelectedIcon={itemIcon}
removeIcon={removeIcon}
clearIcon={clearIcon}
notFoundContent={mergedNotFound}
className={mergedClassName}
getPopupContainer={getPopupContainer || getContextPopupContainer}
dropdownClassName={rcSelectRtlDropDownClassName}
/>
);
};
内部Select,最后用于Select组件的实现,相当于一层封装,同时设计了组件的样式