I thought it would be a simple operation that could be achieved with innerHTML replace, but I encountered many problems. This article records these problems and the final perfect solution, hoping to be helpful to friends who have the same experience. If you are only interested in the results, ignore the process and skip to see the results~
Common practice: regular replacementIdea: If you want to highlight elements, you need to extract the keywords and wrap them in tags, and then adjust the style of the tags. Use innerHTML or outHTML, but not innerText or outText.
const regex = new RegExp(keyword,g)element.innerHTML = element.innerHTML.replace(regex,<b class=a>+keyword+</b>)element.classList.add(highlight)
The hidden dangers of doing this are as follows:
<div id=parent> <div class=test>test</div> </div>
The keyword parent node element performs background dyeing processing through class, which pollutes the original DOM to a certain extent and may affect the repositioning of the element. (As a plug-in, we hope to change the original DOM as little as possible)
Regular optimization one: only process elements located within tagsvar formatKeyword = text.replace(/[-////^$*+?.()|[/]{}]/g, '//$&') // Escape the special characters contained in the keyword, For example, /.var finder = new RegExp(>.*?++.*?<) // Extract the text located in the tag to avoid misoperation of class, id, etc. element.innerHTML = element.innerHTML.replace(finder,function(matched){ return matched.replace(text,<br>+text+</br>)})//Replace keywords in the extracted text within the tag
This can solve most problems, but the problem that still exists is that as long as there is a similar < symbol in the tag attribute, the matching rules will be broken and the regular extraction content will be wrong. HTML5 dataset can customize any content, so these special characters are unavoidable.
<div dataset=p>d>Replace</div>Regular Optimization 2: Clear tags that may be affected
<div id=keyword>keyword</div> =》Replace the closing tag with a variable [replaced1]keyword[replaced2]//The id=keyword in the closing tag will not be processed=》[replaced1]<b>keyword</b >[replaced2] =》Replace the temporary variable replaced with the original tag <div id=keyword><b>keyword</b></div>
This idea and source code come from here, but the problem is:
In short, after N many attempts, various situations have not been effectively handled through regularization. Then I changed my mind and processed it through nodes instead of strings. element.childNodes can most effectively clean up interference information in tags.
[Perfect solution] Processing through DOM nodes<div id=parent> keyword 1 <span id=child> keyword 2 </span> </div>
Get all child nodes through parent.childNodes. The child node can be replaced by innerText.replce(keyword,result) to get the desired highlighting effect, as follows: <span id=child><b>keyword</b> 2</span> (recursive processing: when child Replace operation is performed when the node does not contain child nodes).
However, keyword 1 is a text node and can only modify the text content, cannot add HTML, and cannot control its style independently. Text nodes cannot be converted into ordinary nodes, which is also the most distressing thing.
Finally~, here comes the focus of this article. Because of this function, I came into serious contact with text nodes for the first time. From here I discovered Text, and used the method of cutting text nodes and replacing them to achieve highlighting.
Source code and restore highlights see source code
const reg = new RegExp(keyword.replace(/[-////^$*+?.()|[/]{}]/g, '//$&'))highlight = function (node,reg ){ if (node.nodeType == 3) { //Only process text nodes const match = node.data.match(new RegExp(reg)); if (match) { const highlightEl = document.createElement(b); highlightEl.dataset.highlight=y const wordNode = node.splitText(match.index) wordNode.splitText(match[0].length); // Cut into three Text nodes after the first keyword and const wordNew = document.createTextNode(wordNode.data); highlightEl.appendChild(wordNew);//highlight The node is built successfully wordNode.parentNode.replaceChild(highlightEl, wordNode); // Replace the text node} } else if (node.nodeType == 1 && node.dataset.highlight!=y ) { for (var i = 0; i < node.childNodes.length; i++) { highlight(node.childNodes[i], reg); i++ } } }
Finally, leave an Easter egg. There is also a small bug in the above method. If you are interested, you can find it out.
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.