diff --git a/packages/semi-ui/select/_story/select.stories.jsx b/packages/semi-ui/select/_story/select.stories.jsx index 59790be914..f4c3edb670 100644 --- a/packages/semi-ui/select/_story/select.stories.jsx +++ b/packages/semi-ui/select/_story/select.stories.jsx @@ -2796,7 +2796,13 @@ const FilterDefaultOpen = () => { filter defaultOpen > - + China Korea @@ -3709,4 +3715,71 @@ export const fix2465 = () => { ); -} \ No newline at end of file +} + +export const FilterVirtualizedOptGroupSelect = () => { + const [value, setValue] = useState('a-1'); + + const asiaOptions = Array.from({ length: 50 }, (_, index) => ({ + value: `a-${index + 1}`, + label: `Asia Country ${index + 1}` + })); + + const europeOptions = Array.from({ length: 50 }, (_, index) => ({ + value: `b-${index + 1}`, + label: `Europe Country ${index + 1}` + })); + + const africaOptions = Array.from({ length: 50 }, (_, index) => ({ + value: `c-${index + 1}`, + label: `Africa Country ${index + 1}` + })); + + return ( + + ); +}; + +FilterVirtualizedOptGroupSelect.story = { + name: '分组选择器虚拟化(1000个选项)', + parameters: { + info: { + title: '分组选择器虚拟化', + description: '测试OptGroup是否支持虚拟化' + } + } +}; \ No newline at end of file diff --git a/packages/semi-ui/select/index.tsx b/packages/semi-ui/select/index.tsx index 08fbe874ad..193467bb27 100644 --- a/packages/semi-ui/select/index.tsx +++ b/packages/semi-ui/select/index.tsx @@ -182,14 +182,14 @@ export type SelectProps = { showRestTagsPopover?: boolean; restTagsPopoverProps?: PopoverProps } & Pick< -TooltipProps, -| 'spacing' -| 'getPopupContainer' -| 'motion' -| 'autoAdjustOverflow' -| 'mouseLeaveDelay' -| 'mouseEnterDelay' -| 'stopPropagation' + TooltipProps, + | 'spacing' + | 'getPopupContainer' + | 'motion' + | 'autoAdjustOverflow' + | 'mouseLeaveDelay' + | 'mouseEnterDelay' + | 'stopPropagation' > & React.RefAttributes; export interface SelectState { @@ -316,7 +316,7 @@ class Select extends BaseComponent { }; static __SemiComponentName__ = "Select"; - + static defaultProps: Partial = getDefaultPropsFromGlobalConfig(Select.__SemiComponentName__, { stopPropagation: true, motion: true, @@ -751,7 +751,7 @@ class Select extends BaseComponent { * When searchPosition is trigger, the keyboard events are bound to the outer trigger div, so there is no need to listen in input. * When searchPosition is dropdown, the popup and the outer trigger div are not parent- child relationships, * and bubbles cannot occur, so onKeydown needs to be listened in input. - * */ + * */ onKeyDown: (e) => this.foundation._handleKeyDown(e) }; @@ -924,15 +924,47 @@ class Select extends BaseComponent { const { direction } = this.context; const { height, width, itemSize } = virtualize; + const content: any[] = []; + + visibleOptions.forEach((option) => { + if (option._parentGroup && !content.some(item => + item.type === OptionGroup && + item.props.label === option._parentGroup.label + )) { + content.push( + + ); + } + + content.push(option); + }); + return ( { + if (option.type === OptionGroup) { + return React.cloneElement(option, { style }); + } + return this.renderOption(option, index, style); + } + }} + itemKey={(index, data) => { + const option = data.visibleOptions[index]; + return option.type === OptionGroup + ? `group-${option.props.label}` + : option.value; + }} > {VirtualRow}