Выделение текста с помощью ReactJS
Я пытаюсь выделить текст, соответствующий запросу, но не могу понять, как сделать так, чтобы теги отображались как HTML, а не как текст.
Вот мой код на React:
var Component = React.createClass({
_highlightQuery: function(name, query) {
var regex = new RegExp("(" + query + ")", "gi");
return name.replace(regex, "<strong>$1</strong>");
},
render: function() {
var name = "Javascript";
var query = "java"
return (
<div>
<input type="checkbox" /> {this._highlightQuery(name, query)}
</div>
);
}
});
Текущий вывод: <strong>Java</strong>script
Желаемый вывод: <strong>Java</strong>script
Как я могу отобразить теги как HTML?
5 ответ(ов)
Вот мой простой вспомогательный метод на два строчки:
getHighlightedText(text, highlight) {
// Разделяем текст по ключевому слову, включая его в части, игнорируя регистр
const parts = text.split(new RegExp(`(${highlight})`, 'gi'));
return <span>{parts.map(part => part.toLowerCase() === highlight.toLowerCase() ? <b>{part}</b> : part)}</span>;
}
Этот метод возвращает элемент <span>
, в котором запрашиваемые части выделены с помощью тегов <b> </b>
. При необходимости его можно легко изменить для использования другого тега.
UPDATE: Чтобы избежать предупреждения о наличии уникального ключа, вот решение, основанное на <span>
и установке свойства fontWeight
для совпадающих частей:
getHighlightedText(text, highlight) {
// Разделяем по ключевому слову и включаем его в части, игнорируя регистр
const parts = text.split(new RegExp(`(${highlight})`, 'gi'));
return <span>{parts.map((part, i) =>
<span key={i} style={part.toLowerCase() === highlight.toLowerCase() ? { fontWeight: 'bold' } : {}}>
{part}
</span>)
}</span>;
}
Теперь метод корректно обрабатывает уникальные ключи, что устраняет предупреждения.
Вот пример компонента React, который использует стандартный тег <mark>
для выделения текста:
const Highlighted = ({text = '', highlight = ''}) => {
if (!highlight.trim()) {
return <span>{text}</span>;
}
const regex = new RegExp(`(${_.escapeRegExp(highlight)})`, 'gi');
const parts = text.split(regex);
return (
<span>
{parts.filter(part => part).map((part, i) => (
regex.test(part) ? <mark key={i}>{part}</mark> : <span key={i}>{part}</span>
))}
</span>
);
};
А вот как его использовать:
<Highlighted text="the quick brown fox jumps over the lazy dog" highlight="fox"/>
Этот компонент принимает два пропса: text
(текст для выделения) и highlight
(слово или фраза для поиска). Если highlight
пустой, компонент просто возвращает текст без изменений. В противном случае, он использует регулярное выражение для разделения текста на части и выделения совпадений с помощью тега <mark>
.
По умолчанию ReactJS экранирует HTML для предотвращения XSS-атак. Если вам необходимо установить HTML, вам нужно использовать специальный атрибут dangerouslySetInnerHTML
.
Попробуйте следующий код:
render: function() {
var name = "Javascript";
var query = "java"
return (
<div>
<input type="checkbox" /> <span dangerouslySetInnerHTML={{__html: this._highlightQuery(name, query)}}></span>
</div>
);
}
Обратите внимание, что использование dangerouslySetInnerHTML
подразумевает определенные риски, связанные с безопасностью, поэтому убедитесь, что вводимые данные безопасны и не содержат вредоносного кода.
Ваш код создает компонент Highlight
, который выделяет в тексте совпадения с искомым словом. Давайте разберем его по частям.
Функция escapeRegExp: Эта функция принимает строку и экранирует специальные символы регулярных выражений. Это необходимо, чтобы избежать неожиданных результатов при создании регулярного выражения. Функция использует метод
replace
, чтобы заменить все специальные символы на экранированные версии.const escapeRegExp = (str = '') => ( str.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1') );
Компонент Highlight: Этот компонент принимает два пропса:
search
— строку для поиска иchildren
— текст, в котором будет осуществляться поиск.- Создается регулярное выражение
patt
, которое нежно различает регистры и ищет искомую строку. - Текст разбивается на части с использованием метода
split
, который делит его на массив строк по найденному шаблону. - Если строка для поиска не пуста (
search
), каждая часть проверяется на совпадение с шаблоном. Если совпадение найдено, часть оборачивается в тег<mark>
, что выделяет её на странице. В противном случае возвращается просто текстовая часть.
const Highlight = ({ search = '', children = '' }) => { const patt = new RegExp(`(${escapeRegExp(search)})`, 'i'); const parts = String(children).split(patt); if (search) { return parts.map((part, index) => ( patt.test(part) ? <mark key={index}>{part}</mark> : part )); } else { return children; } };
- Создается регулярное выражение
Использование компонента: В примере использования вы передаете строку "la" для поиска в тексте "La La Land". Компонент выделит все вхождения искомой строки, что, в данном случае, приведет к тому, что буквы "La" будут выделены.
<Highlight search="la">La La Land</Highlight>
Таким образом, данный компонент удобен для выделения искомых фрагментов текста в пользовательском интерфейсе. Вы можете настраивать его для различных строк и контента.
С помощью react-mark.js
вы можете просто использовать следующий код:
<Marker mark="hello">
Hello World
</Marker>
Дополнительные ссылки:
Как реализовать дебаунс?
Обнаружена ошибка: Невозможное нарушение: Неверный тип элемента: ожидался строковый тип (для встроенных компонентов) или класс/функция, но получен объект
Добавление тега script в React/JSX
"Не используйте Route или withRouter() вне Router при работе с react-router 4 и styled-components в React"
React + Redux — Замедление работы onChange в Input при вводе, когда значение берется из состояния