小编典典

botframework Webchat React中的建议列表问题

reactjs

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

1.)
在获得建议的同时,我要在网络建议中输入要在建议列表中加粗的单词。我做到了,但是我现在面临的问题是它只使第一个字母变为粗体(如您在图像中所见),即使它是一种内在感觉,我也想使其变为粗体。

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

3.) 我想使用向上/向下箭头从建议列表中选择选项。

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


阅读 358

收藏
2020-07-22

共1个答案

小编典典

对于第一个问题,可能有两种方法可以做到这一点。为此,您可以使用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>

“危险”警告是因为您需要确保您不允许用户提供任何可能在内部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自动完成软件包(herehere)都具有两个相同的问题:

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

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

键盘事件通常在React中使用onKeyDown属性处理。我将其放置在一个既包含Web聊天又包含您的建议父项的元素上:

<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。您将需要在您的状态中定义一个新属性,以跟踪键盘已选择了哪些建议。我保留了highlightedIndex来自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,
    });
  }
}

为了使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>
2020-07-22