js замена слова на всей странице

256
17 июля 2021, 18:00

Можно ли как-то улучшить код и написать все более эффективно?

Нужно заменить все определенные слова на странице и обнрнуть тегом...

document.body.innerHTML= document.body.innerHTML.replace(new RegExp('word', 'g'), `<h1>глаголъ</h1>');

В данном коде есть сомнения, есть ли эффективным замена всего тела дока., вместо поиска по дереву и замена индивидуальной части. Если, например,

let matches = Array.prototype.slice.call(document.querySelectorAll("body *")).filter(el => el.textContent.includes('word'));

-- тогда если в тексте встречается тег, слово до тега будет заменено, после - нет. можно и с .firstChild.nodeValue уточнать, но мало что меняет. Что странно, при поиске с el.firstChild.nodeValue.includes('word');, если в теге есть, например, <h3>2contain word<span>на wordывоаывол</span>word certin text</h3> span, тогда за ним результат наличия условия уже пробускается, а берется h3 до спана и сам спан, как результаты...

Имеет ли смысл использовать substring ?

обновл: значит, проблема главная в том, что бы вставить html и не обрушить события: el.innerHTML = el.innerHTML.replace(хWord,${хWord})

можно ли взять Node и его value и вставить html в текст как-то?

(в комментах есть ссылки на алгоритмы, но ищу что-то явно проще... как-то vue.js и др. ведь это дело делают)

Answer 1

https://stackoverflow.com/a/31369978

кажется, нашел идеальный вариант

const highlightWord = 'is';
function highlight(element, regex) {
    const document = element.ownerDocument;
    let getNodes = function() {
        let nodes = [],
            offset = 0,
            node,
            nodeIterator = document.createNodeIterator(element, NodeFilter.SHOW_TEXT, null, false);
        while (node = nodeIterator.nextNode()) {
            nodes.push({
                textNode: node,
                start: offset,
                length: node.nodeValue.length
            });
            offset += node.nodeValue.length
        }
        return nodes;
    }
    let nodes = getNodes(this.nodes);
    if (!nodes.length) return;
    let text = '';
    for (let node of nodes)
        text += node.textNode.nodeValue;
    let match;
    while (match = regex.exec(text)) {
        // Prevent empty matches causing infinite loops
        if (!match[0].length) {
            regex.lastIndex++;
            continue;
        }
        // Find the start and end text node
        let startNode = null, endNode = null;
        for (let node of nodes) {
            if (node.start + node.length <= match.index) continue;
            if (!startNode) startNode = node;
            if (node.start + node.length >= match.index + match[0].length) { endNode = node; break; }
        }
        let range = document.createRange();
        range.setStart(startNode.textNode, match.index - startNode.start);
        range.setEnd(endNode.textNode, match.index + match[0].length - endNode.start);
        let spanNode = document.createElement('u');
        spanNode.appendChild(range.extractContents());
        range.insertNode(spanNode);
        nodes = getNodes();
    }
}
const testDiv = document.getElementsByTagName('body')[0];
let originalHtml = testDiv.innerHTML;
(_ => {
    testDiv.innerHTML = originalHtml;
    highlight(testDiv, new RegExp(highlightWord, 'g'));
})()
READ ALSO
разбивка строки на массив

разбивка строки на массив

Как из такой Organization/LimitedCompany/HousingCooperative строки можно сделать массив такого вида: ['Organization', 'Organization/LimitedCompany', 'Organization/LimitedCompany/HousingCooperative']?

172
Nuxt Vuetifi, переопределение стилей scss

Nuxt Vuetifi, переопределение стилей scss

В продакшен версии мои стили перебиваются стилями vuetify

218
document.querySelectorAll() в IE8

document.querySelectorAll() в IE8

Есть возможность заставить работать documentquerySelectorAll('

252
eslint проверяет json файлы

eslint проверяет json файлы

Прописал команду в packagejson:

185