开发者

jquery select elements between two elements that are not siblings

(I've removed attributes, but it's a bit of auto-generated HTML.)

<img class="p"/>
<div> hello world
    <p>
        <font><font size="2">text.<img class="p"/>
        some text
        </font></font>
    </p>
    <img clas开发者_如何学编程s="p"/>
    <p> <font><font size="2">more text<img class="p"/>
        another piece of text
        </font></font>
    </p><img class="p"/> some text on the end
</div>

I need to apply some highlighting with backgrounds to all text that is between two closest (in the HTML code) img.p elements when hovering first of them. I have no idea how to do that. Lets say I hover the first img.p - it should highlight hello world and text. and nothing else.

And now the worst part - I need the backgrounds to disappear on mouseleave.

I need it to work with any HTML mess possible. The above is just an example and structure of the documents will differ.

Tip: Processing the whole html before binding hover and putting some spans etc. is OK as long as it doesn't change the looks of the output document.


Processing the whole html before binding hover and putting some spans etc. is ok

You certainly would have to do that, as you can't style text nodes, only elements.

Here's a function you could use to do it from script. (Unfortunately jQuery isn't much use here as it doesn't like handling text nodes.)

// Wrap Text nodes in a new element of given tagname, when their
// parents contain a mixture of text and element content. Ignore
// whitespace nodes.
//
function wrapMixedContentText(el, tag) {
    var elementcontent= false;
    for (var i= el.childNodes.length; i-->0;) {
        var child= el.childNodes[i];
        if (child.nodeType===1) {
            elementcontent= true;
            wrapMixedContentText(child, tag);
        }
    }
    if (elementcontent) {
        for (var i= el.childNodes.length; i-->0;) {
            var child= el.childNodes[i];
            if (child.nodeType===3 && !child.data.match('^\\s*$')) {
                var wrap= document.createElement(tag);
                el.replaceChild(wrap, child);
                wrap.appendChild(child);
            }
        }
    }
}

And here's some functions that you could use to select nodes between other nodes. (Again, jQuery doesn't currently have a function for this.)

// Get array of outermost elements that are, in document order,
// between the two argument nodes (exclusively).
//
function getElementsBetweenTree(start, end) {
    var ancestor= getCommonAncestor(start, end);

    var before= [];
    while (start.parentNode!==ancestor) {
        var el= start;
        while (el.nextSibling)
            before.push(el= el.nextSibling);
        start= start.parentNode;
    }

    var after= [];
    while (end.parentNode!==ancestor) {
        var el= end;
        while (el.previousSibling)
            after.push(el= el.previousSibling);
        end= end.parentNode;
    }
    after.reverse();

    while ((start= start.nextSibling)!==end)
        before.push(start);
    return before.concat(after);
}

// Get the innermost element that is an ancestor of two nodes.
//
function getCommonAncestor(a, b) {
    var parents= $(a).parents().andSelf();
    while (b) {
        var ix= parents.index(b);
        if (ix!==-1)
            return b;
        b= b.parentNode;
    }
    return null;
}

Possible usage:

var outer= document.getElementById('myhighlightingimagesdiv');
wrapMixedContentText(outer, 'span');

var ps= $('#myhighlightingimagesdiv .p');
ps.each(function(pi) {
    // Go up to the next image in the list, or for the last image, up
    // to the end of the outer wrapper div. (There must be a node
    // after the div for this to work.)
    //
    var end= pi===ps.length-1? outer.nextSibling : ps[pi+1];

    var tweens= $(getElementsBetweenTree(this, end));
    $(this).hover(function() {
        tweens.addClass('highlight');
    }, function() {
        tweens.removeClass('highlight');
    });
});


That is a totally unstructured piece of HTML, which is something you should always avoid. However, you add some data to the img you want to track for hovering, like this:

[...]
<img src="#" class="master" data-friends-group="group1"/>
[...]
<span class="group1">text1</span>
[...]
<span class="group1">text2</span>
[...]

You can now catch from the the "data-friends-group" attribute the class in common to all the elements you need to highlight. Now the rest is easy stuff.

$(document).ready(function() {
    $("img.master").each(function() {
        $friends = $("." + $(this).attr("data-friends-group"));
        $(this).hover(
            function(){
                $friends.addClass("highlighted");
            },
            function(){
                $friends.removeClass("highlighted");
            }
        );
    });
});

Obviously, the class .hightlighted will be the one with the background-color: yellow;

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜