像在 IDE 中一样在文本区域中反应自动完成(例如 VS Code、Atom)

Posted

技术标签:

【中文标题】像在 IDE 中一样在文本区域中反应自动完成(例如 VS Code、Atom)【英文标题】:React autocomplete in a textarea like in an IDE (e.g. VS Code, Atom) 【发布时间】:2019-03-24 12:12:51 【问题描述】:

我尝试在 React 中编写 gif 中的自动完成功能。 因此,在编写文本时会出现建议。

但是到目前为止我能找到的所有软件包都可以工作

a) 仅在输入/文本区域的开头(例如react-autosuggest)

b) 或需要触发字符(如@或#)才能打开(如react-textarea-autocomplete)

我错过了一些 React 限制吗?任何提示/包?

【问题讨论】:

github.com/avcs06/AutoSuggest,这仍处于开发阶段,但它可能是您正在寻找的。​​span> 运气好能找到您的问题的解决方案吗?我也在尝试实现类似的东西。 没有。不幸的是还没有 【参考方案1】:

你可以试试react-predictive-text

【讨论】:

我担心这是一个“经典”的自动完成组件,就像有很多一样,自动完成只针对第一个单词触发。【参考方案2】:

在需要 textarea 实现方面,我实际上遇到了同样的问题,但我可以帮助解决自动完成触发行为。

我们有一个看起来像 person.name 的模板变量的实现,它可以解析为实际值。

关于仅在第一个单词上触发的自动补全,您可以通过对所需功能进行一些修改来解决这个问题。

例如,我所需的功能如下所示。 (不是一个完全可行的例子,但所有重要的部分)


    const templateVars = Object.values(TemplateVarMap);

    const variables = templateVars.map((templateVar) => 
        return 
            name: templateVar,
        ;
    );

    //This func, onChange, and onSuggestionSelected/Highlight are the important
    //parts. We essentially grab the full input string, then slice down to our 
    //autocomplete token and do the same for the search so it filters as you type
    const getSuggestions = (value) => 
        const sliceIndex = value
            .trim()
            .toLowerCase()
            .lastIndexOf(''); //activate autocomplete token
        const inputValue = value
            .trim()
            .toLowerCase()
            .slice(sliceIndex + 2); //+2 to skip over the 
        const inputLength = inputValue.length;
        //show every template variable option once '' is typed, then filter as 
        //they continue to type
        return inputLength === 0
            ? variables
            : variables.filter(
                (variable) => variable.name.toLowerCase().slice(0, inputValue.length) === inputValue
            );
    ;

    const getSuggestionValue = (suggestion) => suggestion.name;

    const renderSuggestion = (suggestion) => <div>suggestion.name</div>;

    onSuggestionsFetchRequested = ( value ) => 
        this.setState(
            suggestions: getSuggestions(value),
        );
    ;

    onSuggestionsClearRequested = () => 
        this.setState(
            suggestions: [],
        );
    ;


    onChange = (event,  newValue ) => 
        //onChange fires on highlight / selection and tries to wipe
        //the entire input to the suggested variable, so if our value
        //is exactly a template variable, don't wipe it 
        if (templateVars.includes(newValue)) 
            return;
        
        this.setState(
            value: newValue,
        );
    ;

    //These both need to do similar things because one is a click selection
    //and the other is selection using the arrow keys + enter, we are essentially
    //manually going through the input and only putting the variable into the
    //string instead of replacing it outright.
    onSuggestionHighlighted = ( suggestion ) => 
        if (!suggestion) 
            return;
        
        const  value  = this.state;
        const sliceIndex = value.lastIndexOf('') + 2;
        const currentVal = value.slice(0, sliceIndex);
        const newValue = currentVal.concat(suggestion.name) + '';
        this.setState( value: newValue );
    ;

    onSuggestionSelected = (event,  suggestionValue ) => 
        const  value  = this.state;
        const sliceIndex = value.lastIndexOf('') + 2;
        const currentVal = value.slice(0, sliceIndex);
        const newValue = currentVal.concat(suggestionValue) + '';
        this.setState( value: newValue );
    ;

    const inputProps = 
        value: this.state.value,
        onChange: this.onChange,
    ;

    render() 
        return (
            <Autosuggest
                suggestions=this.state.suggestions
                onSuggestionSelected=this.onSubjectSuggestionSelected
                onSuggestionHighlighted=this.onSubjectSuggestionHighlighted
                onSuggestionsFetchRequested=this.onSuggestionsFetchRequested
                onSuggestionsClearRequested=this.onSuggestionsClearRequested
                getSuggestionValue=getSuggestionValue
                renderSuggestion=renderSuggestion
                inputProps=inputProps
            />
        )
   

这让我可以输入This is some text with a 之类的内容并弹出自动完成功能,选择一个选项后它应该转到This is some text with a person.name

这里唯一的问题是它需要输入中的最后两个字符是(或任何你的令牌)才能出现自动完成框。我仍然在玩光标移动并以不同的方式切割字符串,所以如果我编辑一个不在末尾的模板,框仍然会弹出。

希望这会有所帮助。

【讨论】:

【参考方案3】:

我们最终使用了出色的编辑器Slate.js。

Mentions example 可以轻松更改,以便任何字符(不仅是“@”)触发建议。你去:完美的自动建议。

【讨论】:

我尝试了一些东西,但无法理解所有内容并找到方法,您能帮帮我吗?你有代码示例要分享吗?

以上是关于像在 IDE 中一样在文本区域中反应自动完成(例如 VS Code、Atom)的主要内容,如果未能解决你的问题,请参考以下文章

获取文本区域中的光标位置

使用 JS 读取文件并在文本区域中显示其内容 [重复]

使用Javascript在文本区域中的光标处插入文本

在文本区域中获取行号[重复]

在文本区域中添加带有热键和javascript的文本

在文本区域中的光标位置之后插入文本