首页 > 解决方案 > 在 ReactBootstrapTypeahead 中选择中间匹配的项目

问题描述

在我的 ReactBootstrapTypeahead 组件中,我可以单击任何选项来选择它,但是Tab如果它在字符串的开头匹配,则 using 只会选择第一个选项。如果第一个选项在中间匹配,则点击Tab仅移动焦点而不选择选项。如果您首先使用箭头键突出显示该选项,它确实有效。

在此处输入图像描述

每个选项都包含一个id,makemodel, 并且我将最后两个组合成name(eg 'Toyota Prius') 以供labelKey. 一切正常,除了选择第一项而不使用箭头键突出显示它。

<AsyncTypeahead
    id="search"
    selectHintOnEnter
    labelKey="name"
    filterBy={startsWith}
    renderMenu={renderMenu}
    options={results}
/>

我正在使用自定义renderMenu函数对选项进行分组...

const renderMenu = (results, menuProps) => {
    const items = [];
    let makesHeader, lastMake, idx = 0;
    results.forEach(result => {
        const { id, make, model } = result;
        if (!make) {
            // skip "click to load more..." text
            items.push(
                <Menu.Header key="more-header">
                    More Results Hidden…
                </Menu.Header>
            );
        }
        else if (!model) {
            if (!makesHeader) {
                items.push(
                    <Menu.Header key="makes-header">
                        Makes
                    </Menu.Header>
                );
                makesHeader = true;
            }
            items.push(
                <MenuItem key={id} option={result} position={idx}>
                    <WordHighlighter search={menuProps.text}>
                        {make}
                    </WordHighlighter>
                </MenuItem>
            );
        }
        else {
            if (make !== lastMake) {
                items.push(
                    <Menu.Header key={`${make}-header`}>
                        {make}
                    </Menu.Header>
                );
                lastMake = make;
            }
            items.push(
                <MenuItem key={id} option={result} position={idx}>
                    <WordHighlighter search={menuProps.text}>
                        {model}
                    </WordHighlighter>
                </MenuItem>
            );
        }
        idx++;
    });
    return <Menu {...menuProps}>{items}</Menu>;
};

...并且仅在任何单词的开头突出显示匹配项。

const WordHighlighter = props => {
    const search = props.search.toLowerCase(),
        len = search.length,
        parts = [];
    let count = 0;
    props.children.split(' ').forEach(word => {
        if (word.toLowerCase().startsWith(search)) {
            parts.push(<mark className="rbt-highlight-text" 
                             key={++count}>{word.substr(0, len)}</mark>);
            parts.push(<span key={++count}>{word.substr(len) + ' '}</span>);
        }
        else {
            parts.push(<span key={++count}>{word + ' '}</span>);
        }
    });
    return <span>{parts}</span>;
};

标签: reactjsreact-bootstrap-typeahead

解决方案


我通过用我自己的覆盖 Typeahead 的onKeyDown回调解决了这个问题。

const typeahead = useRef();

const onChange = useCallback(([ result ]) => {
    typeahead.current.getInstance().clear();
    typeahead.current.getInstance().blur();
    history.push(`/cars/${result.slug}`);
}, [ typeahead ]);

useEffect(() => {
    const instance = typeahead.current.getInstance(),
        original = instance._handleKeyDown;
    instance._handleKeyDown = (e, results, isMenuDown) => {
        if (results && results.length && (e.key === 'Enter' || e.key === 'Tab')) {
            e.preventDefault();
            e.stopPropagation();
            onChange(results);
        }
        else {
            return original(e, results, isMenuDown);
        }
    };
}, [ typeahead, onChange ]);

推荐阅读