如何严格检测相邻的兄弟元素

6
考虑以下HTML,其中ID为#p1#p2#p3的元素是兄弟节点(请参见fiddle):
<div id="container">
    <span id="p1">Paragraph 1</span>
    <span id="p2">Paragraph 2</span>
    This is just loose text.
    <p id="p3">Paragraph 3</p>
</div>

以下是我对严格和松散兄弟姐妹的定义:
- 我认为ID为#p1和#p2的元素是严格兄弟姐妹(因为它们之间没有任何未封装在任何类型的HTML元素中的文本)。 - 而ID为#p2和#p3的元素则是松散兄弟姐妹。
对于任何具有下一个兄弟元素的元素,是否可能知道其下一个兄弟元素是严格还是松散?
注:这些兄弟姐妹可能是不同类型的,我更新了示例以反映这一点。

你想使用css2选择器~+做一些事情 http://www.quirksmode.org/css/selectors/#t11 - Adam Merrifield
我认为更好的术语应该是“相邻元素”或“连续元素”,因为它们都是严格的节点兄弟,只是一个文本节点而不是元素节点。 - Klors
5个回答

4
这是您所指的内容吗:http://cssdeck.com/labs/0blyuslnzv
var isStrict = function(elem1, elem2) {
    "use strict";

    var e1 = document.querySelectorAll(elem1)[0],
        elemNext = document.querySelectorAll(elem1 +" + "+ elem2)[0];

    if (e1.nextSibling.textContent.trim().length) {
        return e1.nextSibling === elemNext;
    } else {
        return e1.nextElementSibling === elemNext;
    }
};

使用示例。

isStrict("head", "body") => true

isStrict("#p1", "#p2") => true

isStrict("#p2", "#p3") => false

2

试试这个。

var $selector = $("#p1");
$selector.siblings().each(function(){
    $(this).addClass('checkSelector');
    if(document.querySelectorAll($selector.selector+' + .checkSelector').length){
        //Do Strict Action
    }else if(document.querySelectorAll($selector.selector+' ~ .checkSelector').length){
        //Do non strict but still sibling action
    }
    $(this).removeClass('checkSelector');
});

http://jsfiddle.net/chsck/5/


2

回答你的问题:

对于任何具有下一个兄弟元素的元素,是否可以知道下一个兄弟元素是严格的还是松散的?

与其跟随你在fiddle中的做法,是的,这是可能的。

function isMyNextSiblingStrict(element)
{
    return ("nodeType" in element && element.nodeType === 1 && element.nextSibling !== null && element.nextSibling.nodeType === 1);
}

当一个元素的下一个兄弟元素是另一个元素时,这将返回true。然而,要小心你的示例,因为按照你自己的定义它是不正确的,两个之间有一个由空格组成的文本节点,所以#1和#2不是“严格的兄弟节点”。

<div id="container">
    <span id="p1">Paragraph 1</span><!-- WHITESPACE
 --><span id="p2">Paragraph 2</span>
    This is just loose text.
    <p id="p3">Paragraph 3</p>
</div>

这些将是“严格的兄弟姐妹”。
<div id="container">
    <span id="p1">Paragraph 1</span><span id="p2">Paragraph 2</span>
    This is just loose text.
    <p id="p3">Paragraph 3</p>
</div>

编辑 - 只是为了好玩,我创建了一个jQuery扩展,应该可以做到你想要的 - 你可以在更新后的jsFiddle中看到它,我没有进行太多测试,但它似乎符合你的描述。

$.fn.extend({
    siblingsStrict: function( until, selector ) {
        var ret = jQuery.map( this, function( elem ) {
            var n = ( elem.parentNode || {} ).firstChild,
                r = [],
                contig = false;

        for ( ; n; n = n.nextSibling ) {
                if ( n === elem ) {
                    contig = true;
                }
                else if ( n.nodeType === 1 && n !== elem ) {
                    r.push( n );
                }
                else if ( n.nodeType === 3 && n.textContent.replace(/\s/g, "") === "" ) {
                    continue;
                }
                else if ( n.nodeType === 3 && contig === true ) {
                    break;
                }
                else if ( n.nodeType === 3 && contig === false) {
                    r = [];
                }
        }

        return r;
    }, until );

        if ( name.slice( -5 ) !== "Until" ) {
            selector = until;
        }

        if ( selector && typeof selector === "string" ) {
            ret = jQuery.filter( selector, ret );
        }

        if ( this.length > 1 ) {
            // Remove duplicates
            if ( !guaranteedUnique[ name ] ) {
                ret = jQuery.unique( ret );
            }

            // Reverse order for parents* and prev-derivatives
            if ( rparentsprev.test( name ) ) {
                ret = ret.reverse();
            }
        }

        return this.pushStack( ret );
    }
});

然而,根据您自己的定义,要小心您的示例是否不正确。今天早上在通勤上班的路上,我在想“我在问题中搞砸了...”但幸运的是有人足够清醒地发现了它... :-) 我会审查和测试所有答案,并在今天晚些时候选择一个。 - Fabricio
我正在测试你的第一个解决方案,但是出现了控制台错误:Firefox显示“TypeError: invalid 'in' operand element”,Opera显示“Uncaught exception: TypeError: Operator 'in' applied to non-object”,Chrome也出现问题:“Uncaught TypeError: Cannot use 'in' operator to search for 'nodeType' in #p1”。请参见fiddle。你有什么想法? - Fabricio
我不确定,不幸的是我看不到你的fiddle,这里有一个fiddle http://jsfiddle.net/chsck/12/ - Klors
虽然我很难理解扩展代码中正在发生什么,但它确实回答了我的问题... +1。事实上,我忘记放我的 fiddle 了。在里面,我试图使用 isMyNextSiblingStrict("#p1") 调用函数,这是我想要做的事情的一个打字错误。但是在看到你最后的 fiddle 后,顺便说一句,它完美地工作了,我也修复了我的错误,并尝试使用 isMyNextSiblingStrict($("#p1")) 调用函数,但它总是返回 FALSE。我以为 $("#p1")document.getElementById("p1") 是相同的,但似乎并不是这样... [chat]? - Fabricio
$("#p1") 返回的是一个 jQuery 对象,而 document.getElementById("p1") 返回的是一个 DOM 节点。你可以通过 $("#p1")[0] 或 $("#p1").eq(0) 从 jQuery 中获得相同的结果。没见过这个聊天工具,真新鲜。不用担心扩展代码,它大部分只是从 jQuery 的方法定义中复制过来的 .siblings。关键在于.map中的中间函数。 - Klors

0
忽略其他人可能写的内容;
function checkAdjacency(element1,element2){
    var result = isLooseOrStrict(element1,element2);
    if(result != 'not'){
        return result;
    }
    else{
        return isLooseOrStrict(element2,element1);    
    }
}

function isLooseOrStrict(elemName1, elemName2){
    var element = document.getElementById(elemName1);
    var element2 =  document.getElementById(elemName2);

    if(element.nextSibling.nodeType != 3){
        if(element.nextSibling == elem2){
            return 'strict';
        }
    }
    else if(element.nextSibling.nextSibling == element2){
        if(element.nextSibling.nodeValue.trim() != '')
            return 'loose';
        else
            return 'strict';
    }
    return 'not';
}

-1

你可以只使用以下代码来实现这个功能:

(jsFiddle -> http://jsfiddle.net/Castrolol/chsck/4/ )

function getSiblings(elem){    
    var siblings = [];
    var actualElem = elem;
    while(actualElem = actualElem.nextSibling ){
        if( !actualElem.textContent.trim() ) continue;
        siblings.push({
            elem: actualElem,
            isStrict: !(actualElem instanceof Text)
        });
    }
    return siblings;
}

//using the function
var element = $("#p1").get(0);
var siblings = getSiblings(element);
siblings.forEach(function(sibling){
    if( sibling.isStrict ) {
        //here is a tag
        sibling.elem.style.color = "red";
    }else{
        //here not is a tag        
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接