Blueprint 的Select组件正是我当前的 React 项目所需要的,但有一个例外:我需要在它的弹出框中添加一些元素,但看不到任何方法。
具体来说,我想在过滤器输入上方添加一个标题(例如 H2 元素),并在列表下方添加一个按钮栏(例如,DIV 中的一些 Button 组件)。选择似乎高度可配置,但我看不到在弹出框内添加元素的方法......我错过了什么?
Blueprint 的Select组件正是我当前的 React 项目所需要的,但有一个例外:我需要在它的弹出框中添加一些元素,但看不到任何方法。
具体来说,我想在过滤器输入上方添加一个标题(例如 H2 元素),并在列表下方添加一个按钮栏(例如,DIV 中的一些 Button 组件)。选择似乎高度可配置,但我看不到在弹出框内添加元素的方法......我错过了什么?
如果要扩展选择的菜单并向其添加自定义元素,则必须提供itemListRenderer
道具。
默认情况下,Select 在菜单中呈现显示的项目。可以通过提供itemListRenderer 属性来覆盖此行为,让您完全控制项目的布局。例如,您可以将项目分组到一个共同的标题下,或者使用 react-virtualized 渲染大型数据集。
itemListRenderer示例:
如果提供,将调用 itemListRenderer 属性来渲染下拉菜单的内容。它可以访问项目、当前查询和用于呈现单个项目的 renderItem 回调。还给出了一个 ref 处理程序(itemsParentRef);它应该附加到渲染菜单项的父元素,以便当前选定的项目可以自动滚动到视图中。
因此,Menu
您可以在组件的主体中放置自定义标题和按钮:
import { ItemListRenderer } from "@blueprintjs/select";
const renderMenu: ItemListRenderer<Film> = ({ items, itemsParentRef, query, renderItem }) => {
const renderedItems = items.map(renderItem).filter(item => item != null);
return (
<Menu ulRef={itemsParentRef}>
<h2>Your heading can be styled here</h2>
<MenuItem
disabled={true}
text={`Found ${renderedItems.length} items matching "${query}"`}
/>
{renderedItems}
<div>
<button>Button name</button>
</div>
</Menu>
);
};
<FilmSelect
itemListRenderer={renderMenu}
itemPredicate={filterFilm}
itemRenderer={renderFilm}
items={...}
onItemSelect={...}
/>
乔丹的上述建议,加上一些实验,最终得出了一个可行的答案:
filterable
为 false 以隐藏内置过滤器输入。itemListRenderer
呈现下拉项,还用于呈现 InputGroup 以用作替换过滤器。inputRef
prop 捕获对底层 HTML 输入的引用。onOpening
通过Select 的popoverProps
prop属性,在输入出现时使用它来聚焦输入。这是一个实现上述内容的简单组件:
// Extends Blueprint's Select component with header and footer props that
// can be any arbitrary elements or components
class ExtendedSelect extends Component {
constructor(props) {
super(props);
this.inputRef = null;
this.state = {query: ""};
}
handleInputChanged = event => {
this.setState({query: event.target.value});
}
receiveInputRef = (ref) => {
this.inputRef = ref;
}
handlePopoverOpening = () => {
if (this.inputRef) {
this.inputRef.focus();
}
}
listRenderer = ({filteredItems, renderItem}) => {
// Apply the supplied item renderer to the filtered list of items
const renderedItems = filteredItems.map(renderItem);
return (
<div>
{this.props.header}
<InputGroup inputRef={this.receiveInputRef} value={this.state.query} onChange={this.handleInputChanged} leftIcon="search" />
<Menu>
{renderedItems}
</Menu>
{this.props.footer}
</div>
);
}
render() {
return (
<Select
items={this.props.items}
filterable={false}
query={this.state.query}
itemListRenderer={this.listRenderer}
itemPredicate={this.props.itemPredicate}
itemRenderer={this.props.itemRenderer}
popoverProps={{onOpening:this.handlePopoverOpening}}
onItemSelect={this.props.onItemSelect}
>
{this.props.children}
</Select>
);
}
}
(请注意,我只是将 Select 的一些 props 传递到自定义组件中——我怀疑如果我是一个更有经验的 React 开发人员,我会知道一种方法来传递它们。)
这工作得非常好——例如,除了在输入出现时聚焦输入的一些工作之外,Select 的所有其他内置行为都按预期工作,例如在输入聚焦时菜单的键盘导航。