jQuery第一个父包含所有子节点

时间:2010-07-09 23:27:58

标签: jquery html

我如何选择包含所有这些元素的一组元素的第一个父元素?

例如:

<body>
 <dl>
  <dt>Items:</dt>
  <dd>
   <ul>
    <li>Item 1<div class="item-info">...</div></li>
    <li>Item 2<div class="item-info">...</div></li>
    <li>Item 3<div class="item-info">...</div></li>
   </ul>
  </dd>
 </dl>
</body>

我想要这样的事情:

$('.item-info').commonParent();

它将返回相当于:

[$('ul')]

使用jQuery选择器有一种简单的方法吗?或者我要写一个插件?

11 个答案:

答案 0 :(得分:9)

如果您确实在寻找最低共同祖先(See this working in a fiddle):

jQuery.fn.commonAncestor = function() {
  var parents = [];
  var minlen = Infinity;

  $(this).each(function() {
    var curparents = $(this).parents();
    parents.push(curparents);
    minlen = Math.min(minlen, curparents.length);
  });

  for (var i in parents) {
    parents[i] = parents[i].slice(parents[i].length - minlen);
  }

  // Iterate until equality is found
  for (var i = 0; i < parents[0].length; i++) {
    var equal = true;
    for (var j in parents) {
      if (parents[j][i] != parents[0][i]) {
        equal = false;
        break;
      }
    }
    if (equal) return $(parents[0][i]);
  }
  return $([]);
}

实施例

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="jquery.commonancestor.js"></script>


$(function() {
  console.log($(".item-info").commonAncestor());
});
</script>
<body>
 <dl>
  <dt>Items:</dt>
  <dd>
   <ul>
    <li>Item 1<b><div class="item-info">...</div></b></li>
    <li>Item 2<u><div class="item-info">...</div></u></li>
    <li>Item 3<i><div class="item-info">...</div></i></li>
   </ul>
  </dd>
 </dl>
</body>

这尚未经过严格测试,因此请指出您看到的任何错误。

编辑返回父级而非$(父级)

编辑在IE8中无效

答案 1 :(得分:2)

我认为重点在于.item-info元素(可能)遍布整个页面。

如果这是正确的,试试这个: http://jsfiddle.net/EJWjf/1/

var $items = $('.item-info');   // Cache all the items in question
var total = $items.length;      // Cache the total number
var parent;                     // Will store the match

$items.first()           // Grab the first item (an arbitrary starting point)
    .parents()           // Get all of its parent elements
    .each(function() {
            // Iterate over each parent, finding the .info-item elements
            //    it contains, and see if the quantity matches the total
        if($(this).find('.item-info').length == total) {
            parent = this;  // If so, we found the closest common ancestor so
            return false;   //     store it and break out of the loop
        }
    });

alert(parent.tagName);

这是一个功能版本:http://jsfiddle.net/EJWjf/2/

function findCommon(selector) {
    var $items = $(selector);   
    var total = $items.length;      
    var parent;                   

    $items.first()
        .parents()
        .each(function() {
            if($(this).find(selector).length == total) {
                parent = this;
                return false;
            }
        });

    return $(parent);
}

var result = findCommon('.item-info');

答案 2 :(得分:1)

这是我的版本。它是页面上所有jQuery-plugin类型答案的performs best。它是唯一一个处理空jQuery对象$()而没有错误的对象。它和Jamie Wong的答案是唯一能够无错误地处理单项jQuery对象的答案。

我建造了a jsfiddle showcasing all the versions' output。您可以单击“预设”按钮以轻松查看不同的测试用例,或者输入您自己的选择器并单击“查找”以查看结果。

jQuery.fn.reverse = function() {
   return Array.prototype.reverse.call(this);
};

jQuery.fn.commonAncestor = function() {
   var i, l, current,
      compare = this.eq(0).parents().reverse(),
      pos = compare.length - 1;
   for (i = 1, l = this.length; i < l && pos > 0; i += 1) {
      current = this.eq(i).parents().reverse();
      pos = Math.min(pos, current.length - 1);
      while (compare[pos] !== current[pos]) {
         pos -= 1;
      }
   }
   return compare.eq(pos);
};

在其中一个元素是另一个元素的祖先的情况下,到目前为止给出的所有答案都返回祖先元素的父元素。上述两个链接都包含我的函数版本,例如,如果页面上有div,$('body, div').commonAncestor()将返回body而不是html

注意:此函数假定jQuery集中的所有项都在当前文档中。将两个不同文档中的元素放入同一个jQuery对象中需要特别的,奇怪的努力 - 在这种情况下,我的函数将失败(页面上的所有其他文档也将失败)。这可以从将条件pos > 0更改为pos >= 0开始,使while循环句柄达到-1,并可能将return compare.eq(pos)更改为return $(compare[pos])(因为eq( )函数使用负索引从末尾向后索引而不是返回空)。

答案 3 :(得分:1)

这个比其他所有人(包括ErikE&#39; s)快得多,特别是对于很多元素:

&#13;
&#13;
jQuery.fn.commonAncestor = function() {
  if (!this.length)
    return null;

  var parent = this[0].parentNode;
  for (var i = this.length - 1; i >= 1; --i) {
    var elt = this[i];
    if (elt.contains(parent))
      parent = elt.parentNode;
    else
      while (!parent.contains(elt))
        parent = parent.parentNode;
  }
  return parent;
};
&#13;
&#13;
&#13;

答案 4 :(得分:0)

你在寻找这些吗?

$("element").parents() // return all parents until reaches 'html'

$("element").parent() // return the first parent

$("element").closest("parent") // return the closest selected parent

答案 5 :(得分:0)

我相信这就是你要找的东西:

<强>的jQuery

前四行包含实际抓取UL的代码。其余的只是显示匹配的UL的内容。

<script type="text/javascript">
  $(document).ready(function() {
    // The code that grabs the matching ULs
    var ULsWithAll=$("ul").has(".item-info").filter( function(index) { // Grab all ULs that has at least one .item-info
      var ChildrenOfUL=$(this).children("li");  // Grab the children

      return ChildrenOfUL.length===ChildrenOfUL.has(".item-info").length;  // Are all of them .item-info
    });

    $(ULsWithAll).each(function(){ // Output the ULs that were found
      alert($(this).html());
    })
  });
</script>

<强> HTML

<dl>
  <dt>Items 1:</dt>
  <dd>
    <ul>
      <li>Item 1-1<div class="item-info">...</div></li>
      <li>Item 1-2<div class="item-info">...</div></li>
      <li>Item 1-3<div class="item-info">...</div></li>
    </ul>
  </dd>
  <dt>Items 2:</dt>
  <dd>
    <ul>
      <li>Item 2-1<div class="item-info">...</div></li>
      <li>Item 2-2<div class="item-info">...</div></li>
      <li>Item 2-3<div class="item-info">...</div></li>
    </ul>
  </dd>
  <dt>Items 3:</dt>
  <dd>
    <ul>
      <li>Item 3-1<div class="item-info">...</div></li>
      <li>Item 3-2<div class="item-info">...</div></li>
      <li>Item 3-3<div>...</div></li>
    </ul>
  </dd>
</dl>

上面的jQuery代码将返回第一次和第二次命中的UL(第三次是dud)。请在http://jsfiddle.net/ksTtF/

处查看

另一个例子(没有警报):http://jsfiddle.net/vQxGC/

答案 6 :(得分:0)

受到各种其他答案的启发,我创建了一个符合我要求的版本。 http://jsfiddle.net/qDRv5/(请注意,它将找到的父级写入控制台)

jQuery.fn.firstParent=function (f){
    //Set the variables for use;
    s=$(this);
    var i,j;
    var p=[];
    var pv=true;

    //make sure there is something to itterate over
    if(s.length>0){

        //build a multidimentional array of parents
        s.each(function(){p.push($(this).parents());});

        //itterate through the parents of the first element starting at the closest
        for(i=0;i<p[0].length;i++){

            //itterate through all elements after the first
            for(j=1;j<s.length;j++){

                //look for the current parent of the first element in each array
                pv=($.inArray(p[0][i],p[j]) != -1);

                //if we are looking at the last element and it matchs, return that parent
                if(pv==true && j==s.length-1) return typeof(f)=='string'?$(p[0][i]).find(f):$(p[0][i]);
            }
        }
    }
    return false;
}

我首先从root查找元素最少的步骤,因为我确信这个元素不会有一个远离root的共同祖先。 然后我一次从父母退回,从那些元素检查父元素是否具有所有其他元素作为子元素。当我找到一个包含所有元素作为孩子的父元素时,我的任务就完成了。

答案 7 :(得分:0)

你忘记了吗? ......这只是Javascript ......

$('.item-info').get(0).parentElement

答案 8 :(得分:0)

所以...我知道这是一个旧线程,但我需要这个确切的功能,并且需要它在jQuery的漂亮链中工作;)所以这就是我想出的:

jQuery.fn.firstParent=function (f){
    //Set the variables for use;
    s=$(this);
    var i,j;
    var p=[];
    var pv=true;

    //make sure there is something to itterate over
    if(s.length>0){

        //build a multidimentional array of parents
        s.each(function(){p.push($(this).parents());});

        //itterate through the parents of the first element starting at the closest
        for(i=0;i<p[0].length;i++){

            //itterate through all elements after the first
            for(j=1;j<s.length;j++){

                //look for the current parent of the first element in each array
                pv=($.inArray(p[0][i],p[j]) != -1);

                //if we are looking at the last element and it matchs, return that parent
                if(pv==true && j==s.length-1) return typeof(f)=='string'?$(p[0][i]).find(f):$(p[0][i]);
            }
        }
    }
    return false;
}

还有一个jsfiddle here

答案 9 :(得分:0)

我会这样做:过滤出选择器父项,它包含选择器集中的每个元素。

jQuery.fn.commonParent = function() {
  var parent = this.parents();
  this.each(function() {
    parent = parent.has(this);
  });
  return parent.first();
};

答案 10 :(得分:0)

8年后,面对同样的问题,我最终来到了这里。这些答案都不是我想要的,所以我最终得到了这个答案。它可能不是绝对最快的,但它很小而直接:

$.fn.commonParents = function () {
  var $children = this.toArray();
  // reduce the parents to those where
  return this.parents().filter(function (i, parent) {
    // every child
    return $children.every(function (child) {
      // is contained by a that parent
      return $.contains(parent, child);
    });
  });
};

获取最接近的信息:

var $closestCommonParent = $elements.commonParents().first();