jQuery查找与表达式匹配的所有先前元素

时间:2008-11-27 04:14:43

标签: javascript jquery

使用jQuery,如何匹配DOM树中当前元素之前的元素?使用prevAll()仅匹配以前的兄弟节点。

例如:

<table>
    <tr>
        <td class="findme">find this one</td>
    </tr>
    <tr>
        <td><a href="#" class="myLinks">find the previous .findme</a></td>
    </tr>
    <tr>
        <td class="findme">don't find this one</td>
    </tr>
</table>

在我的具体情况下,我会在点击链接之前搜索第一个 .findme元素。

5 个答案:

答案 0 :(得分:20)

好的,这就是我想出的 - 希望它在许多不同情况下都有用。这是jQuery的2个扩展,我称之为prevALLnextALL。虽然标准prevAll()与之前的兄弟姐妹匹配,但prevALL()会匹配所有以前的元素,一直到DOM树,同样适用于nextAll()nextALL()

我会尝试在下面的评论中解释它:

// this is a small helper extension i stole from
// http://www.texotela.co.uk/code/jquery/reverse/
// it merely reverses the order of a jQuery set.
$.fn.reverse = function() {
    return this.pushStack(this.get().reverse(), arguments);
};

// create two new functions: prevALL and nextALL. they're very similar, hence this style.
$.each( ['prev', 'next'], function(unusedIndex, name) {
    $.fn[ name + 'ALL' ] = function(matchExpr) {
        // get all the elements in the body, including the body.
        var $all = $('body').find('*').andSelf();

        // slice the $all object according to which way we're looking
        $all = (name == 'prev')
             ? $all.slice(0, $all.index(this)).reverse()
             : $all.slice($all.index(this) + 1)
        ;
        // filter the matches if specified
        if (matchExpr) $all = $all.filter(matchExpr);
        return $all;
    };
});

用法:

$('.myLinks').click(function() {
    $(this)
        .prevALL('.findme:first')
        .html("You found me!")
    ;

    // set previous nodes to blue
    $(this).prevALL().css('backgroundColor', 'blue');

    // set following nodes to red
    $(this).nextALL().css('backgroundColor', 'red');
});

编辑 - 从头开始​​重写的功能。我只是想到了一种更快捷,更简单的方法。看一下编辑历史,看看我的第一次迭代。

再次编辑 - 找到了一种更简单的方法!

答案 1 :(得分:1)

据推测,您在onclick处理程序中执行此操作,因此您可以访问被单击的元素。我要做的是做一个prevAll来看它是否处于同一水平。如果没有,那么我会做一个parent()。prevAll()来获取父元素的前一个兄弟,然后迭代这些兄弟元素,检查它们的内容是否有所需的元素。继续向上移动DOM树,直到找到你想要的或者命中DOM的根。这是一种通用算法。

如果您知道它在一个表中,那么您可以简单地获取包含该元素的行,并从该行向后遍历该表的行,直到找到包含所需元素的行。

我认为没有办法在一个(链式)声明中做到这一点。

答案 2 :(得分:1)

修改:此解决方案适用于您的原始问题,您在第一条评论中提到的问题,以及之后评论中详细说明的问题。

$('.myLinks').click(function() {
    var findMe = '';

    $(this).parents().each(function() {
        var a = $(this).find('.findme').is('.findme');
        var b = $(this).find('.myLinks').is('.myLinks');
        if (a && b) {                             // look for first parent that
                                                  // contains .findme and .myLinks
            $(this).find('*').each(function() {
                var name = $(this).attr('class');
                if ( name == 'findme') {
                    findMe = $(this);             // set element to last matching
                                                  // .findme
                }
                if ( name == 'myLinks')    {
                    return false;                 // exit from the mess once we find
                                                  // .myLinks
                }
            });
            return false;
        }   
    });
    alert(findMe.text() );               // alerts "find this one"
});

这适用于OP中的示例以及注释中所述的修改示例:

<table>
  <tr>
    <td class="findme">don't find this one</td>
  </tr>
  <tr>
    <td class="findme">find this one</td>
  </tr>
  <tr>
    <td><a href="#" class="myLinks">find the previous .findme</a></td>
  </tr>
  <tr>
    <td class="findme">don't find this one</td>
  </tr>
</table>

以及您添加的此测试用例:

<table>
  <tr>
    <td class="findme">don't find this one</td>
  </tr>
  <tr>
    <td class="findme">don't find this one</td>
  </tr>
  <tr>
    <td class="findme">find this one</td>
  </tr>
</table>

<a href="#" class="myLinks">find the previous .findme</a>

答案 3 :(得分:1)

我通常对元素(1,2,3 ..)(rel =“number”)进行编号,因此我使用此代码为所有以前的元素提供类:

var num = $(this).attr("rel");

for (var i = 1; i<=num; i++)
{
    $('.class[rel="'+i+'"]').addClass("newclass");
}

答案 4 :(得分:0)

有同样的问题,这是我提出的问题。我的函数使用compareDocumentPosition。不知道它在性能方面与其他解决方案的比较。

$.fn.findNext = function ( selector ) {
  var found, self = this.get(0);
  $( selector )
    .each( function () {
      if ( self.compareDocumentPosition( this ) === 4 ){ 
        found = this; 
        return false;
      }    
    })
  return $(found);
}

当然,人们可以很容易地改变这一点来获取调用元素之后的所有元素。

$.fn.nextALL= function ( selector ) {
  var found = [], self = this.get(0);
  $( selector )
    .each( function () {
      if ( self.compareDocumentPosition( this ) === 4 )
        found.push(this);          
    })
  return $(found);
}

编辑:精简版

$.fn.findNext = function( s ){
    var m = this[0], f=function(n){return m.compareDocumentPosition(n)===4;};
    return this.pushStack( $(s).get().filter(f) );
}