Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
549 views
in Technique[技术] by (71.8m points)

javascript: find strings in dom and emphasize it

i want a function that finds some strings i've got in an array in the DOM and emphasize it.

eg.

keywords[0] = 'linux';
keywords[1] = 'suse pro';

<body>
    im a huge fan of <em>linux</em> and at the moment im using <em>suse pro</em> and finds it amazing.
</body>

how do i do it in the easiest way. thanks in advance

EDIT: i found a very easy way to accomplish this: jquery highlight plugin! cheers!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I had to do this a couple of months ago. Originally someone used string manipulation of innerHTML as suggested by others here but that road leads to madness. The troublesome corner cases are: What if the keyword being marked up is an element's class name or id. We also don't want to mangle any embedded javascript and accidentally cause invalid markup. Also need to handle embedded css styles. In the end you end up writing a text parser for HTML4.0 + ECMAscript + css which, even in the limited case, is a lot of work - it's writing your own web browser - IN JAVASCRIPT!

But we already have a HTML+JS+CSS parser in the web browser that generates a nice DOM tree for us. So I decided to use that. This is what I came up with in the end:

keywords = ['hello world','goodbye cruel world'];
function replaceKeywords (domNode) {
    if (domNode.nodeType === Node.ELEMENT_NODE) { // We only want to scan html elements
        var children = domNode.childNodes;
        for (var i=0;i<children.length;i++) {
            var child = children[i];

            // Filter out unwanted nodes to speed up processing.
            // For example, you can ignore 'SCRIPT' nodes etc.
            if (child.nodeName != 'EM') {
                replaceKeywords(child); // Recurse!
            }
        }
    }
    else if (domNode.nodeType === Node.TEXT_NODE) { // Process text nodes
        var text = domNode.nodeValue;

        // This is another place where it might be prudent to add filters

        for (var i=0;i<keywords.length;i++) {
            var match = text.indexOf(keywords[i]); // you may use search instead
            if (match != -1) {
                // create the EM node:
                var em = document.createElement('EM');

                // split text into 3 parts: before, mid and after
                var mid = domNode.splitText(match);
                mid.splitText(keywords[i].length);

                // then assign mid part to EM
                mid.parentNode.insertBefore(em,mid);
                mid.parentNode.removeChild(mid);
                em.appendChild(mid);
            }
        }
    }
}

As long as you're careful about filtering out things you don't want to process (for example, empty text nodes that contain only whitespace - there are lots of them, trust me) this is very fast.

Additional filtering not implemented for algorithmic clarity - left as an exercise to the reader.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.8k users

...