向 Blueprint Select 组件弹出框添加元素?
Add elements to Blueprint Select component popover?
Blueprint 的 Select 组件正是我当前的 React 项目所需要的,但有一个例外:我需要向其弹出窗口添加一些元素,但看不到任何方法。
具体来说,我想在过滤器输入上方添加一个标题(例如 H2 元素),并在列表下方添加一个按钮栏(例如 DIV 中的一些按钮组件)。 Select 似乎高度可配置,但我看不到在弹出框内添加元素的方法...我错过了什么?
如果您想扩展 select 的菜单并向其添加自定义元素,则必须提供 itemListRenderer
属性。
By default, Select renders the displayed items in a Menu. This
behavior can be overridden by providing the itemListRenderer prop,
giving you full control over the layout of the items. For example, you
can group items under a common heading, or render large data sets
using react-virtualized.
itemListRenderer 示例:
If provided, the itemListRenderer prop will be called to render the contents of the dropdown menu. It has access to the items, the current query, and a renderItem callback for rendering a single item. A ref handler (itemsParentRef) is given as well; it should be attached to the parent element of the rendered menu items so that the currently selected item can be scrolled into view automatically.
因此,在 Menu
组件的 body 中,您可以放置自定义标题和按钮:
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={...}
/>
Jordan 的上述建议,加上一些实验,最终产生了一个可行的答案:
- 将
filterable
设置为 false 以隐藏内置过滤器输入。
- 使用
itemListRenderer
不仅可以呈现下拉项,还可以呈现一个 InputGroup 作为替换过滤器。
- 使用 InputGroup 的
inputRef
属性捕获对基础 HTML 输入的引用。通过 Select 的 popoverProps
prop. 的 onOpening
属性 使用它来聚焦输入
这是一个实现上述内容的简单组件:
// 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 的所有其他内置行为都按预期工作,比如菜单的键盘导航,同时输入被聚焦。
Blueprint 的 Select 组件正是我当前的 React 项目所需要的,但有一个例外:我需要向其弹出窗口添加一些元素,但看不到任何方法。
具体来说,我想在过滤器输入上方添加一个标题(例如 H2 元素),并在列表下方添加一个按钮栏(例如 DIV 中的一些按钮组件)。 Select 似乎高度可配置,但我看不到在弹出框内添加元素的方法...我错过了什么?
如果您想扩展 select 的菜单并向其添加自定义元素,则必须提供 itemListRenderer
属性。
By default, Select renders the displayed items in a Menu. This behavior can be overridden by providing the itemListRenderer prop, giving you full control over the layout of the items. For example, you can group items under a common heading, or render large data sets using react-virtualized.
itemListRenderer 示例:
If provided, the itemListRenderer prop will be called to render the contents of the dropdown menu. It has access to the items, the current query, and a renderItem callback for rendering a single item. A ref handler (itemsParentRef) is given as well; it should be attached to the parent element of the rendered menu items so that the currently selected item can be scrolled into view automatically.
因此,在 Menu
组件的 body 中,您可以放置自定义标题和按钮:
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={...}
/>
Jordan 的上述建议,加上一些实验,最终产生了一个可行的答案:
- 将
filterable
设置为 false 以隐藏内置过滤器输入。 - 使用
itemListRenderer
不仅可以呈现下拉项,还可以呈现一个 InputGroup 作为替换过滤器。 - 使用 InputGroup 的
inputRef
属性捕获对基础 HTML 输入的引用。通过 Select 的popoverProps
prop. 的
onOpening
属性 使用它来聚焦输入
这是一个实现上述内容的简单组件:
// 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 的所有其他内置行为都按预期工作,比如菜单的键盘导航,同时输入被聚焦。