botframework Webchat React 中的建议列表问题
Issues with suggestion list in botframework Webchat React
我刚刚使用 react.js 在我的 bot-framework 网络聊天 (v-4) 中添加了 autosuggestion/autocomplete 功能。但是有些问题我需要解决;
1.) 在收到建议时,我想在生成的建议列表中将我在网络聊天中输入的字词设为粗体。我这样做了,但我现在面临的问题是它只能将第一个字母设为粗体(如图所示)我想将其设为粗体,即使它在句子中也是如此。
2.) 当我 select 从建议列表中选择一个选项时,它必须被关闭。它会关闭其他选项,但 selected 选项不会。(如图所示)。我也想关闭它。
3.) 我想为建议列表中的 selecting 选项制作 up/down 箭头。
请在下面的链接中找到图片,
对于你的第一个问题,可能有两种方法可以做到这一点。要以 React 的方式做到这一点,您可以使用 indexOf
在建议中查找用户文本的索引,然后将文本拆分为多个 React 元素,其中一个以粗体显示。如果您想像现在一样使用 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>
"dangerous" 警告是因为您需要确保您不允许用户提供任何可以进入内部 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 将如何工作时,你必须考虑很多设计注意事项,比如 "What happens if the user mouses over the suggestions while they're using the arrow keys?" 和 "Should the highlighted suggestion be previewed in the send box before the user presses enter?" 我希望找到一个预先存在的 React 自动完成组件,您可以使用它而不是构建自己的组件,因为它已经解决了所有这些潜在的陷阱。不幸的是,两个著名的 React 自动完成包 (here and here) 都有两个相同的问题:
- 它们目前没有得到维护
- 目标输入包含在组件中,因此您无需将组件连接到预先存在的输入。
但是,它们都是开源的,因此我们可以仿照它们构建我们自己的自动完成功能。我将引导您完成基本功能,您可以根据需要对其进行扩展。
键盘事件通常在 React 中使用 onKeyDown
属性 处理。我已将其放置在包含网络聊天和您的建议的元素上 parent:
<div className={ROOT_CSS} onKeyDown={this.handleKeyDown.bind(this)}>
<div className={WEB_CHAT_CSS + ''}>
<ReactWebChat
这将处理所有按键操作,因此您需要一种方法来路由到正确键的函数。您可以使用 switch
语句,但 react-autocomplete 的源代码使用查找对象,我认为这很聪明。
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
。您将需要在您的状态中定义一个新的 属性 以跟踪键盘选择了哪个建议。我从 react-autocomplete 中保留名称 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,
});
}
}
对于应用建议的回车键,您需要集中您的功能,以便它的工作方式与鼠标单击相同。
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>
我刚刚使用 react.js 在我的 bot-framework 网络聊天 (v-4) 中添加了 autosuggestion/autocomplete 功能。但是有些问题我需要解决;
1.) 在收到建议时,我想在生成的建议列表中将我在网络聊天中输入的字词设为粗体。我这样做了,但我现在面临的问题是它只能将第一个字母设为粗体(如图所示)我想将其设为粗体,即使它在句子中也是如此。
2.) 当我 select 从建议列表中选择一个选项时,它必须被关闭。它会关闭其他选项,但 selected 选项不会。(如图所示)。我也想关闭它。
3.) 我想为建议列表中的 selecting 选项制作 up/down 箭头。
请在下面的链接中找到图片,
对于你的第一个问题,可能有两种方法可以做到这一点。要以 React 的方式做到这一点,您可以使用 indexOf
在建议中查找用户文本的索引,然后将文本拆分为多个 React 元素,其中一个以粗体显示。如果您想像现在一样使用 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>
"dangerous" 警告是因为您需要确保您不允许用户提供任何可以进入内部 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 将如何工作时,你必须考虑很多设计注意事项,比如 "What happens if the user mouses over the suggestions while they're using the arrow keys?" 和 "Should the highlighted suggestion be previewed in the send box before the user presses enter?" 我希望找到一个预先存在的 React 自动完成组件,您可以使用它而不是构建自己的组件,因为它已经解决了所有这些潜在的陷阱。不幸的是,两个著名的 React 自动完成包 (here and here) 都有两个相同的问题:
- 它们目前没有得到维护
- 目标输入包含在组件中,因此您无需将组件连接到预先存在的输入。
但是,它们都是开源的,因此我们可以仿照它们构建我们自己的自动完成功能。我将引导您完成基本功能,您可以根据需要对其进行扩展。
键盘事件通常在 React 中使用 onKeyDown
属性 处理。我已将其放置在包含网络聊天和您的建议的元素上 parent:
<div className={ROOT_CSS} onKeyDown={this.handleKeyDown.bind(this)}>
<div className={WEB_CHAT_CSS + ''}>
<ReactWebChat
这将处理所有按键操作,因此您需要一种方法来路由到正确键的函数。您可以使用 switch
语句,但 react-autocomplete 的源代码使用查找对象,我认为这很聪明。
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
。您将需要在您的状态中定义一个新的 属性 以跟踪键盘选择了哪个建议。我从 react-autocomplete 中保留名称 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,
});
}
}
对于应用建议的回车键,您需要集中您的功能,以便它的工作方式与鼠标单击相同。
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>