我想创建一个完全受控的下拉菜单,以便使用https://tools.ietf.org/html/rfc6570#page-18在其中显示很长的项目列表。
我已经检查过文档,并且没有任何指定Dropdown.Item
的受控下拉菜单的例子。
这是我的组件的样子:
<Dropdown
placeholder="Filter Posts"
clearable={true}
search={true}
onChange={this.handleChange}
text={tagOptions[1].value}
value={tagOptions[1].value}
onSearchChange={this.handleChange}
>
<Dropdown.Menu>
{tagOptions.map(option => (
<Dropdown.Item key={option.value} {...option} onClick={this.handleItemClick} />
))}
</Dropdown.Menu>
</Dropdown>;
我遇到了2个问题:
options
属性,它将找不到给定值,因此将不显示该值。我可以使用text
属性,但这似乎很简单。handleItemClick
,我发现react-window中存在逻辑。有什么建议吗?我在这里错过了什么吗?
答案 0 :(得分:2)
dropdown模块根本不支持对其内部组件的控制,也就是说,这是我最接近使用react-window支持的受控dropdown。我将其发布在这里,供以后希望通过虚拟化轻松选择下拉菜单的任何人。
import React, { forwardRef, useCallback, useRef, useState } from "react"
import { Dropdown, Ref } from "semantic-ui-react"
import { FixedSizeList } from "react-window"
import "./VirtualisedDropdown.scss"
const SUI_DROPDOWN_MENU_HEIGHT = 300
const SUI_DROPDOWN_MENU_ITEM_HEIGHT = 37
const VirtualisedDropdown = ({
options, value,
...restProps
}) => {
const dropdownRef = useRef()
const listRef = useRef()
const [open, setOpen] = useState(false)
const OuterDiv = useCallback(({ style, ...props }, ref) => {
const { position, overflow, ...restStyle } = style
return (
<Ref innerRef={ref}>
<Dropdown.Menu open={open} {...props} style={restStyle}>
{props.children}
</Dropdown.Menu>
</Ref>
)
}, [open])
const InnerDiv = useCallback(props => {
return (
<Dropdown.Menu className="inner" open={open} style={{ ...props.style, maxHeight: props.style.height }}>
{props.children}
</Dropdown.Menu>
)
}, [open])
return (
<Dropdown
className="virtualised selection"
onClose={() => setOpen(false)}
onOpen={() => {
setOpen(true)
listRef.current.scrollToItem(options.findIndex(i => i.value === value))
}}
// This causes "Warning: Failed prop type: Prop `children` in `Dropdown` conflicts with props: `options`. They cannot be defined together, choose one or the other."
// but is necessary for some logic to work e.g. the selected item text.
options={options}
ref={dropdownRef}
selectOnNavigation={false}
value={value}
{...restProps}
>
<FixedSizeList
height={options.length * SUI_DROPDOWN_MENU_ITEM_HEIGHT < SUI_DROPDOWN_MENU_HEIGHT ? options.length * SUI_DROPDOWN_MENU_ITEM_HEIGHT + 1 : SUI_DROPDOWN_MENU_HEIGHT}
innerElementType={InnerDiv}
itemCount={options.length}
itemData={{
options,
handleClick: (_e, x) => dropdownRef.current.handleItemClick(_e, x),
selectedIndex: options.findIndex(i => i.value === value),
}}
itemSize={SUI_DROPDOWN_MENU_ITEM_HEIGHT}
outerElementType={forwardRef(OuterDiv)}
ref={listRef}
>
{Row}
</FixedSizeList>
</Dropdown>
)
}
const Row = ({ index, style, data }) => {
const { options, handleClick, selectedIndex } = data
const item = options[index]
return (
<Dropdown.Item
active={index === selectedIndex}
className="ellipsis"
key={item.value}
onClick={handleClick}
selected={index === selectedIndex}
style={style}
title={item.text}
{...item}
/>
)
}
export default VirtualisedDropdown
.ui.dropdown.virtualised .menu {
&.inner {
margin: 0 -1px !important;
left: 0;
overflow: initial;
border-radius: 0 !important;
border: 0;
}
> .item {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
答案 1 :(得分:1)
我可以使用下拉菜单中的ref并传递原始的handleItemClick
方法来破解它。
目前唯一的缺点是键盘导航无效:\
似乎并非旨在对其进行完全控制。
答案 2 :(得分:0)
要解决第一个问题,请删除clearable={true}
和text={tagOptions[1].value}
handleItemClick
函数应该做什么?