前言
Select 是最频繁使用的UI组件之一,它可以运用在很多场景。大多数情况下,原生HTML的<Select>
标签无法满足业务的功能过需求,以及原生HTML的<Select>
标签在各个浏览器版本里样式表现不太一样。在这样的情况下,多数人都会选择实现一个符合UI要求以及产品功能需求的Select组件,或者选择使用一些开源组件库提供的 Select 组件。本文主要梳理了 gio-design 中的Select组件在实现过程中遇到的一些阻碍及需要注意的地方,希望能对大家在设计和实现select组件时提供一些帮助。
数据源(dataSource)
Select 组件的两种使用方法:
// 第一种写法
const options = [{label:'a',value:'a'},{label:'b',value:''b}];
<Select options={options} />
// 第二种
<Select>
<Select.Option value={'a'} >a</Select.Option>
<Select.Option value={'b'} >b</Select.Option>
</Select>
使用 Select 组件的时候,一般情况下,有两种方式来设定 dataSource。
- 通过
options
参数,传入纯数据格式。 JSX
,通过拦截子组件<Select.Option/>
的参数,转化为nodeOptions
。相比较JSX
而言,options
参数形式拥有更好的性能(JSX
方式最终也会转为类似options
参数的形式)。
该转换方式借鉴了rc-select 中的写法。
export function convertChildrenToData(nodes: React.ReactNode, group = {}): Option[] {
let nodeOptions: Option[] = [];
React.Children.forEach(nodes, (node: React.ReactElement & { type: { isSelectOptGroup?: boolean }; props: OptionProps }) => {
if (!React.isValidElement(node)) return;
const {
type: { isSelectOptGroup },
props: { children, label, value },
} = node;
if (!isSelectOptGroup) { // option
nodeOptions.push(convertNodeToOption(node, group));
} else { // Group
nodeOptions = concat(nodeOptions, convertChildrenToData(children, { groupLabel: label, groupValue: value }));
}
});
return nodeOptions;
}
// ReactNode To Options
export function convertNodeToOption(node: React.ReactElement, group: group): Option {
const {
props: { value, children, ...restProps },
} = node as React.ReactElement & { props: OptionProps };
const { groupValue, groupLabel } = group;
if (groupLabel && groupLabel) {
return { value, label: children !== undefined ? children : value, groupValue, groupLabel, ...restProps };
}
return { value, label: children !== undefined ? children : value, ...restProps };
}
Group
和 Option
的定义:
// group
export interface OptionGroupFC extends React.FC<OptGroupProps> {
isSelectOptGroup: boolean;
}
export const OptGroup: OptionGroupFC = () => null;
OptGroup.isSelectOptGroup = true;
export default OptGroup;
// option
export interface OptionFC extends React.FC<OptionProps> {
isSelectOption: boolean;
}
const Option: OptionFC = () => null;
Option.isSelectOption = true;
export default Option;
上面这个两个方法思路也比较清晰,用 isSelectOptGroup
来区分 Group
和 Option
。Group
会在 Option
原有参数上额外增加 groupLabel 和 groupValue 两个 key。
当两种传