На ваш первый вопрос может быть два способа сделать это. Чтобы сделать это способом 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>
«Опасное» предупреждение заключается в том, что вы должны не позволяют пользователю предоставлять какие-либо потенциальные значения, которые могут go во внутреннем 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.
Для вашего третьего вопроса есть много конструктивных соображений, которые вы должны задать себе о том, как выяснить, как будет работать ваш пользовательский интерфейс, например: «Что произойдет, если пользователь наводит подсказки на подсказки, когда они используют клавиши со стрелками?» и "Следует ли предварительно просмотреть выделенное предложение в поле отправки до того, как пользователь нажмет ввод?" Я надеялся найти уже существующий компонент автозаполнения React, который вы могли бы использовать вместо создания своего собственного, потому что он уже устранял бы все эти потенциальные ловушки. К сожалению, два известных пакета автозаполнения React ( здесь и здесь ) имеют одинаковые две проблемы:
- В настоящее время они не поддерживаются
- Целевой вход включен в компонент, поэтому вы не можете подключить компонент к уже существующему входу.
Тем не менее, они оба с открытым исходным кодом, поэтому мы можем моделировать наше собственное автозаполнение функциональность после них. Я проведу вас через основные функции c, и вы сможете расширить их по своему усмотрению.
События клавиатуры, как правило, обрабатываются в React с использованием свойства onKeyDown
. Я поместил его в элемент, содержащий как веб-чат, так и родительский элемент ваших предложений:
<div className={ROOT_CSS} onKeyDown={this.handleKeyDown.bind(this)}>
<div className={WEB_CHAT_CSS + ''}>
<ReactWebChat
, который будет обрабатывать все нажатия клавиш, поэтому вам понадобится способ указать правильную клавишу для функции. , Вы можете использовать оператор switch
, но исходный код для response-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
от реагирования-автозаполнения.
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>