Ну какого-то встроенного готового изящного решения наверное нет. Я вижу лишь вариант самописной (или использовать готовую библиотеку) функции (утилиты) под собственные нужды.
Например вот функция оборачивающая исключительно в span. Один из недостатков функции в том, что она опирается на `matchAll` метод поддерживаемый вроде бы пока еще не всеми браузерами.
Параметры:
- строка в которой производится поиск и замена
- искомая строка (может быть регулярное выражение, но обязательно с `g` флагом)
- необязательное значение класса для span (чтоб не печатать нужно любое falthy значение - null, '', 0, false)
- необязательное значение порядкового индекса найденного совпадения для оборачивания. по умолчанию - `0`. может иметь негативное значе `-1` для последнего значения сколько бы их не было, `-2` для предпоследнего и тд.
const spanText = (str, pattern, className = '', index = 0) => {
const matches = [...str.matchAll(pattern)];
if (!matches.length || !matches.slice(index)[0]) return str;
const { 0: match, index: startIndex } = matches.slice(index)[0];
const endIndex = startIndex + match.length
const spanOpenTag = !className ? '<span>' : `<span class="${className.toString()}">`;
return str.slice(0, startIndex) + spanOpenTag + match + '<span>' + str.slice(endIndex);
}
const re = new RegExp(word, 'g');
text.innerHTML = spanText(text.innerHTML, re);