向 Blueprint Select 组件弹出框添加元素?

Add elements to Blueprint Select component popover?

Blueprint 的 Select 组件正是我当前的 React 项目所需要的,但有一个例外:我需要向其弹出窗口添加一些元素,但看不到任何方法。

具体来说,我想在过滤器输入上方添加一个标题(例如 H2 元素),并在列表下方添加一个按钮栏(例如 DIV 中的一些按钮组件)。 Select 似乎高度可配置,但我看不到在弹出框内添加元素的方法...我错过了什么?

如果您想扩展 select 的菜单并向其添加自定义元素,则必须提供 itemListRenderer 属性。

Here's what the docs says:

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 的上述建议,加上一些实验,最终产生了一个可行的答案:

  1. filterable 设置为 false 以隐藏内置过滤器输入。
  2. 使用 itemListRenderer 不仅可以呈现下拉项,还可以呈现一个 InputGroup 作为替换过滤器。
  3. 使用 InputGroup 的 inputRef 属性捕获对基础 HTML 输入的引用。通过 Select 的 popoverProps prop.
  4. 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 的所有其他内置行为都按预期工作,比如菜单的键盘导航,同时输入被聚焦。