botframework Webchat React 中的建议列表问题 [英] Issues with suggestion list in botframework Webchat React

查看:34
本文介绍了botframework Webchat React 中的建议列表问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚使用 react.js 在我的机器人框架网络聊天 (v-4) 中添加了自动建议/自动完成功能.但是有一些问题我需要解决;

1.) 在获得建议的同时,我想让我在网络聊天中输入的单词在结果建议列表中加粗.我这样做了,但我现在面临的问题是它只是将第一个字母设为粗体(如您在图像中看到的),即使它在句子中,我也想将其设为粗体.

2.) 当我从建议列表中选择一个选项时,它必须关闭.它关闭其他选项,但所选选项不是.(如图所示).我也想关闭它.

3.) 我想制作用于从建议列表中选择选项的向上/向下箭头.

请在以下链接中找到图片,

解决方案

对于您的第一个问题,可能有两种方法可以做到这一点.要以 React 方式执行此操作,您可以使用 indexOf 在建议中查找用户文本的索引,然后将文本拆分为多个 React 元素,其中一个以粗体显示.如果您想像当前一样使用 replace,那么这可能是使用 dangerouslySetInnerHTML 的好机会:

{this.state.suggestions.map(suggestion => (<div className="Suggestion" onClick={this.handleSuggestionClick} ><div risklySetInnerHTML={this.getSuggestionHtml(suggestion)}/>

))}

危险"警告是因为您需要确保不允许用户提供任何可以进入内部 HTML 的潜在值,否则他们可能会注入脚本标签.只要您的建议是从固定数据库中提取的并且数据是安全的,那么您可能没问题.否则,您将不得不清理 HTML,在这种情况下,根本不使用 dangerouslySetInnerHTML 可能会更容易.如果我们确实设置了内部 HTML,那么我们可以使用 replace 直接将 HTML 标记应用于字符串:

getSuggestionHtml(suggestion) {const lowerCaseSuggestion =Suggestion.toLowerCase();返回 {__html:lowerCaseSuggestion.includes(this.state.suggestionTypedText) ?小写建议.replace(this.state.suggestionTypedText, `<b>${this.state.suggestionTypedText}</b>`) :lowerCaseSuggestion};}

对于你的第二个问题,你说你已经解决了.我可以看到您正在使用布尔开关暂时关闭您响应 WEB_CHAT/SET_SEND_BOX 操作的方式.

对于您的第三个问题,在确定您的 UI 将如何工作时,您必须问自己很多设计注意事项,例如如果用户在使用时将鼠标悬停在建议上会发生什么?方向键?"和在用户按下 Enter 键之前,是否应该在发送框中预览突出显示的建议?"我希望找到一个预先存在的 React 自动完成组件,您可以使用它而不是构建自己的组件,因为这已经解决了所有这些潜在的陷阱.不幸的是,两个突出的 React 自动完成包(这里这里) 两者都有相同的两个问题:

  1. 它们目前没有得到维护
  2. 目标输入包含在组件中,因此您无法将组件连接到预先存在的输入.

但是,它们都是开源的,因此我们可以在它们之后为我们自己的自动完成功能建模.我将指导您完成基本功能,您可以根据需要进行扩展.

键盘事件通常在 React 中使用 onKeyDown 属性处理.我已将它放在一个包含网络聊天和您的父母建议的元素上:

<div className={WEB_CHAT_CSS + ''}><ReactWebChat

这将处理所有按键操作,因此您需要一种方法来路由到正确键的功能.您可以使用 switch 语句,但是 react-autocomplete 使用查找对象,我认为这很聪明.

keyDownHandlers = {向下箭头(事件){this.moveHighlight(事件, 1);},箭头向上(事件){this.moveHighlight(event, -1);},输入(事件){const {建议} = this.state;如果(!建议.长度){//菜单已关闭,因此没有可以接受的选择 ->没做什么返回}event.preventDefault()this.applySuggestion(suggestions[this.state.highlightedIndex]);},}handleKeyDown(事件){如果(this.keyDownHandlers[event.key])this.keyDownHandlers[event.key].call(this, event)}

我已将向上和向下箭头的功能集中到一个函数中:moveHighlight.您将需要在您的状态中定义一个新属性,以跟踪键盘选择了哪个建议.我保留了 react-autocomplete 中的 highlightedIndex 名称.

moveHighlight(事件,方向){event.preventDefault();const { 高亮索引,建议 } = this.state;如果(!建议.长度)返回;让 newIndex = (highlightedIndex + 方向 + 建议长度) % 建议长度;如果(新索引!== 高亮索引){this.setState({高亮索引:新索引,});}}

对于应用建议的回车键,您需要集中您的功能,以便它的工作方式与鼠标单击相同.

async handleSuggestionClick(event) {等待 this.applySuggestion(event.currentTarget.textContent);}异步应用建议(新值){等待 this.setState({ typingChecking: "false", 建议: [], highlightIndex: 0 });this.state.suggestionCallback.dispatch({类型:'WEB_CHAT/SET_SEND_BOX',有效载荷:{文本:新值,}});等待 this.setState({ typingChecking: "true" });}

最后,确保 highlightedIndex 属性用于以不同的方式呈现突出显示的索引.

getSuggestionCss(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 risklySetInnerHTML={this.getSuggestionHtml(suggestion)}/>

))}

I just added autosuggestion/autocomplete function in my bot-framework web chat(v-4) using react.js. But there are some issues i need to fix;

1.) While getting the suggestions i want to make the words which i type into the webchat to be Bold in the resulting suggestion list. I did that but the problem i'm facing now is that its only making the first letter as bold(as you can see in the image) i want to make it bold even if its inside a sentance.

2.) When i select an option from the suggestion list it has to be closed. It closes the other options but the selected option is not.(as shown in the image). I want to close that too.

3.) I want to make my up/down arrow for selecting options from the suggestion list.

Please find the images in below links,

解决方案

For your first question, there may be two ways to do this. To do it the React way, you could use indexOf to find the index of the user text in the suggestion and then split the text into multiple React elements with one of them being bolded. If you want to use replace like you're currently doing then this may be a good opportunity to use dangerouslySetInnerHTML:

<div className="SuggestionParent" id="Suggestion1">
  {this.state.suggestions.map(suggestion => (
    <div className="Suggestion" onClick={this.handleSuggestionClick} >
      <div dangerouslySetInnerHTML={this.getSuggestionHtml(suggestion)} />
    </div>
  ))}
</div>

The "dangerous" warning is because you need to make sure you don't allow the user to provide any of the potential values that can go in the inner HTML or else they could inject script tags. As long as your suggestions are being drawn from a fixed database and the data is secure then you might be okay. Otherwise you would have to sanitize the HTML and in that case it would probably be easier to just not use dangerouslySetInnerHTML at all. If we do set the inner HTML, then we can use replace to just directly apply HTML tags to the string:

getSuggestionHtml(suggestion) {
  const lowerCaseSuggestion = suggestion.toLowerCase();
  return {
    __html: lowerCaseSuggestion.includes(this.state.suggestionTypedText) ? lowerCaseSuggestion
      .replace(this.state.suggestionTypedText, `<b>${this.state.suggestionTypedText}</b>`) : lowerCaseSuggestion
  };
}

For your second question, you said you've already solved it. I can see that you're using a Boolean switch to temporarily turn off the way you respond to the WEB_CHAT/SET_SEND_BOX action.

For your third question, there are a lot of design considerations that you have to ask yourself about when figuring out how your UI is going to work, like "What happens if the user mouses over the suggestions while they're using the arrow keys?" and "Should the highlighted suggestion be previewed in the send box before the user presses enter?" I was hoping to find a preexisting React autocomplete component that you could use instead of building your own because that would already address all these potential pitfalls. Unfortunately, the two prominent React autocomplete packages (here and here) both have the same two problems:

  1. They're not currently being maintained
  2. The targeted input is included in the component so you don't get to connect the component to a preexisting input.

However, they are both open source so we can model our own autocomplete functionality after them. I'll guide you through the basic functionality and you can expand on that as you please.

Keyboard events are generally handled in React using the onKeyDown property. I've placed it on an element that contains both Web Chat and your suggestions parent:

<div className={ROOT_CSS} onKeyDown={this.handleKeyDown.bind(this)}>
  <div className={WEB_CHAT_CSS + ''}>
    <ReactWebChat

That will handle all key presses, so you'll need a way to route to the function for the correct key. You could use a switch statement but the source code for react-autocomplete uses a lookup object and I think that's smart.

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)
}

I've centralized the functionality for the up and down arrows into one function: moveHighlight. You will need to define a new property in your state to keep track of which suggestion has been selected by the keyboard. I'm keeping the name highlightedIndex from react-autocomplete.

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,
    });
  }
}

For the enter key to apply a suggestion, you'll want to centralize your functionality so that it works the same way as a mouse click.

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" });
}

Finally, make sure the highlightedIndex property is used to render the highlighted index differently.

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>

这篇关于botframework Webchat React 中的建议列表问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
C#最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆