Это функция, которую я написал несколько лет назад, которая ищет определенный текст и выделяет его (помещает совпадения в span
с определенным именем класса).
Проходит по DOM-дереву, изучая текстовое содержимое. Всякий раз, когда он находит текстовый узел, содержащий искомый текст, он заменяет этот текстовый узел тремя новыми узлами:
- один текстовый узел с текстом, предшествующим совпадению,
- один (недавно созданный)
span
элемент, содержащий соответствующий текст,
- и один текстовый узел с текстом после совпадения.
Это та функция, которая у меня есть. Это часть большого файла сценария, но он также должен работать независимо. (Я прокомментировал вызов ensureElementVisible
, который сделал элемент видимым, поскольку сценарий также имел возможности свертывания и расширения).
Он делает одну (другую) вещь, которая вам, вероятно, не понадобится: он превращает текст поиска в регулярное выражение, соответствующее любому из нескольких слов.
function findText(a_text, a_top) {
// Go through *all* elements below a_top (if a_top is undefined, then use the body)
// and check the textContent or innerText (only if it has textual content!)
var rexPhrase = new RegExp(a_text.replace(/([\\\/\*\?\+\.\[\]\{\}\(\)\|\^\$])/g, '\\$1').replace(/\W+/g, '\\W*')
, 'gi');
var terms = [];
var rexSearchTokens = /[\w]+/g;
var match;
while(match = rexSearchTokens.exec(a_text)) {
terms.push(match[0]);
}
var rexTerm = new RegExp('\\b(' + terms.join('|') + ')', 'gi');
var hits = [];
walkDOMTree(a_top || document.body,
function search(a_element) {
if (a_element.nodeName === '#text') {
if(rexPhrase.test(a_element.nodeValue)) {
// ensureElementVisible(a_element, true);
hits.push(a_element);
}
}
});
// highlight the search terms in the found elements
for(var i = 0; i < hits.length; i++) {
var hit = hits[i];
var parent = hit.parentNode;
if (parent.childNodes.length === 1) {
// Remove the element from the hit list
hits.splice(i, 1);
var text = hit.nodeValue;
parent.removeChild(hit);
var match, prevLastIndex = 0;
while(match = rexTerm.exec(text)) {
parent.appendChild(document.createTextNode(text.substr(prevLastIndex, match.index - prevLastIndex)));
var highlightedTerm = parent.appendChild(document.createElement('SPAN'));
highlightedTerm.className = 'search-hit';
highlightedTerm.appendChild(document.createTextNode(match[0]));
prevLastIndex = match.index + match[0].length;
// Insert the newly added element into the hit list
hits.splice(i, 0, highlightedTerm);
i++;
}
parent.appendChild(document.createTextNode(text.substr(prevLastIndex)));
// Account for the removal of the original hit node
i--;
}
}
return hits;
}