我只是使用react.js在我的机器人框架网络聊天(v-4)中添加了自动提示/自动完成功能。但是我需要解决一些问题。
1.) 在获得建议的同时,我要在网络建议中输入要在建议列表中加粗的单词。我做到了,但是我现在面临的问题是它只使第一个字母变为粗体(如您在图像中所见),即使它是一种内在感觉,我也想使其变为粗体。
2.) 当我从建议列表中选择一个选项时,必须将其关闭。它会关闭其他选项,但不会关闭其他选项。(如图所示)。我也想结束。
3.) 我想使用向上/向下箭头从建议列表中选择选项。
请在以下链接中找到图片,
对于第一个问题,可能有两种方法可以做到这一点。为此,您可以使用React方式indexOf在建议中查找用户文本的索引,然后将文本拆分为多个React元素,其中一个元素以粗体显示。如果您想像replace现在一样使用,那么这可能是一个使用的好机会dangerouslySetInnerHTML:
indexOf
replace
dangerouslySetInnerHTML
<div className="SuggestionParent" id="Suggestion1"> {this.state.suggestions.map(suggestion => ( <div className="Suggestion" onClick={this.handleSuggestionClick} > <div dangerouslySetInnerHTML={this.getSuggestionHtml(suggestion)} /> </div> ))} </div>
“危险”警告是因为您需要确保您不允许用户提供任何可能在内部HTML中使用的潜在值,否则他们可能会注入脚本标签。只要您的建议是从固定的数据库中提取的并且数据是安全的,那么您就可以了。否则,您将必须清理HTML,在这种情况下,根本不使用它可能会更容易dangerouslySetInnerHTML。如果我们确实设置了内部HTML,则可以replace用来直接将HTML标签应用于字符串:
getSuggestionHtml(suggestion) { const lowerCaseSuggestion = suggestion.toLowerCase(); return { __html: lowerCaseSuggestion.includes(this.state.suggestionTypedText) ? lowerCaseSuggestion .replace(this.state.suggestionTypedText, `<b>${this.state.suggestionTypedText}</b>`) : lowerCaseSuggestion }; }
对于第二个问题,您说您已经解决了。我可以看到您正在使用布尔开关暂时关闭对WEB_CHAT / SET_SEND_BOX操作的响应方式。
对于第三个问题,在弄清UI的工作方式时,您需要问自己很多设计注意事项,例如“如果用户在使用箭头键时将鼠标悬停在建议上,会发生什么? ” 和“是否应在用户按下Enter之前在发送框中预览突出显示的建议?” 我希望找到一个可以使用的React自动完成组件,而不用自己构建它,因为这已经解决了所有这些潜在的陷阱。不幸的是,两个著名的React自动完成软件包(here和here)都具有两个相同的问题:
但是,它们都是开源的,因此我们可以在它们之后建模自己的自动完成功能。我将指导您完成基本功能,然后您可以根据需要对其进行扩展。
键盘事件通常在React中使用onKeyDown属性处理。我将其放置在一个既包含Web聊天又包含您的建议父项的元素上:
onKeyDown
<div className={ROOT_CSS} onKeyDown={this.handleKeyDown.bind(this)}> <div className={WEB_CHAT_CSS + ''}> <ReactWebChat
这将处理所有按键操作,因此您需要一种方法来路由至正确按键的功能。您可以使用一条switch语句,但是react- autocomplete的源代码使用查找对象,我认为这很聪明。
switch
keyDownHandlers = { ArrowDown(event) { this.moveHighlight(event, 1); }, ArrowUp(event) { this.moveHighlight(event, -1); }, Enter(event) { const {suggestions} = this.state; if (!suggestions.length) { // menu is closed so there is no selection to accept -> do nothing return } event.preventDefault() this.applySuggestion(suggestions[this.state.highlightedIndex]); }, } handleKeyDown(event) { if (this.keyDownHandlers[event.key]) this.keyDownHandlers[event.key].call(this, event) }
我已经将向上和向下箭头的功能集中到一个功能中:moveHighlight。您将需要在您的状态中定义一个新属性,以跟踪键盘已选择了哪些建议。我保留了highlightedIndex来自react- autocomplete 的名称。
moveHighlight
highlightedIndex
moveHighlight(event, direction) { event.preventDefault(); const { highlightedIndex, suggestions } = this.state; if (!suggestions.length) return; let newIndex = (highlightedIndex + direction + suggestions.length) % suggestions.length; if (newIndex !== highlightedIndex) { this.setState({ highlightedIndex: newIndex, }); } }
为了使Enter键应用建议,您需要集中化功能,以便其与单击鼠标相同。
async handleSuggestionClick(event) { await this.applySuggestion(event.currentTarget.textContent); } async applySuggestion(newValue) { await this.setState({ typingChecking: "false", suggestions: [], highlightedIndex: 0 }); this.state.suggestionCallback.dispatch({ type: 'WEB_CHAT/SET_SEND_BOX', payload: { text: newValue, } }); await this.setState({ typingChecking: "true" }); }
最后,确保使用该highlightedIndex属性以不同的方式呈现突出显示的索引。
getSuggestionCss(index) { return index === this.state.highlightedIndex ? HIGHLIGHTED_CSS : SUGGESTION_CSS; } . . . <div className="SuggestionParent" id="Suggestion1"> {this.state.suggestions.map((suggestion, index) => ( <div className={this.getSuggestionCss(index)} key={index} onClick={this.handleSuggestionClick} > <div dangerouslySetInnerHTML={this.getSuggestionHtml(suggestion)} /> </div> ))} </div>