2

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

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

4

2 回答 2

2

如果要扩展选择的菜单并向其添加自定义元素,则必须提供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={...}
/>
于 2018-09-04T08:25:02.393 回答
1

乔丹的上述建议,加上一些实验,最终得出了一个可行的答案:

  1. 设置filterable为 false 以隐藏内置过滤器输入。
  2. 不仅用于itemListRenderer呈现下拉项,还用于呈现 InputGroup 以用作替换过滤器。
  3. 使用 InputGroup 的inputRefprop 捕获对底层 HTML 输入的引用。onOpening通过Select 的popoverPropsprop属性,在输入出现时使用它来聚焦输入。

这是一个实现上述内容的简单组件:

// 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 的所有其他内置行为都按预期工作,例如在输入聚焦时菜单的键盘导航。

于 2018-09-05T14:00:53.997 回答