代码之家  ›  专栏  ›  技术社区  ›  Gnuffo1

jquery查找某个类的next/prev元素,但不一定是兄弟元素

  •  16
  • Gnuffo1  · 技术社区  · 16 年前

    next、prev、nextall和prevall方法非常有用,但如果要查找的元素不在同一父元素中,则不会。我想做的是这样的事情:

    <div>
        <span id="click">Hello</span>
    </div>
    <div>
        <p class="find">World></p>
    </div>
    

    当跨度与ID click 按下,我想将下一个元素与类匹配 find ,在本例中,它不是单击元素的兄弟,因此 next() nextAll() 不起作用。

    5 回复  |  直到 12 年前
        1
  •  8
  •   Michael Clerx    15 年前

    今天我自己也在解决这个问题,我想到的是:

    /**
     * Find the next element matching a certain selector. Differs from next() in
     *  that it searches outside the current element's parent.
     *  
     * @param selector The selector to search for
     * @param steps (optional) The number of steps to search, the default is 1
     * @param scope (optional) The scope to search in, the default is document wide 
     */
    $.fn.findNext = function(selector, steps, scope)
    {
        // Steps given? Then parse to int 
        if (steps)
        {
            steps = Math.floor(steps);
        }
        else if (steps === 0)
        {
            // Stupid case :)
            return this;
        }
        else
        {
            // Else, try the easy way
            var next = this.next(selector);
            if (next.length)
                return next;
            // Easy way failed, try the hard way :)
            steps = 1;
        }
    
        // Set scope to document or user-defined
        scope = (scope) ? $(scope) : $(document);
    
        // Find kids that match selector: used as exclusion filter
        var kids = this.find(selector);
    
        // Find in parent(s)
        hay = $(this);
        while(hay[0] != scope[0])
        {
            // Move up one level
            hay = hay.parent();     
            // Select all kids of parent
            //  - excluding kids of current element (next != inside),
            //  - add current element (will be added in document order)
            var rs = hay.find(selector).not(kids).add($(this));
            // Move the desired number of steps
            var id = rs.index(this) + steps;
            // Result found? then return
            if (id > -1 && id < rs.length)
                return $(rs[id]);
        }
        // Return empty result
        return $([]);
    }
    

    所以在你的例子中

    <div><span id="click">hello</span></div>
    <div><p class="find">world></p></div>
    

    现在可以使用

    $('#click').findNext('.find').html('testing 123');
    

    我怀疑它在大型结构上的性能会很好,但这里是:)

        2
  •  13
  •   lordvlad    12 年前

    试试这个。它将标记元素,创建一组与选择器匹配的元素,并从元素后面的集合中收集所有元素。

    $.fn.findNext = function ( selector ) {
        var set = $( [] ), found = false;
        $( this ).attr( "findNext" , "true" );
        $( selector ).each( function( i , element ) {
            element = $( element );
            if ( found == true ) set = set.add( element )
            if ( element.attr("findNext") == "true" ) found = true;
        })
        $( this ).removeAttr( "findNext" )
        return set
    }
    

    编辑

    使用jquerys索引方法的更简单的解决方案。但是,从中调用方法的元素需要由相同的选择器进行选择

    $.fn.findNext = function( selector ){
        var set = $( selector );
        return set.eq( set.index( this, ) + 1 )
    }
    

    为了让这个功能摆脱这个障碍,我们可以使用浏览器自己的功能。 compareDocumentposition

    $.fn.findNext = function ( selector ) {
      // if the stack is empty, return the first found element
      if ( this.length < 1 ) return $(s).first();
      var found,
          that = this.get(0);
      $( selector )
        .each( function () {
           var pos = that.compareDocumentPosition( this );
           if ( pos === 4 || pos === 12 || pos === 20 ){
           // pos === 2 || 10 || 18 for previous elements 
             found = element; 
             return false;
           }    
        })
      // using pushStack, one can now go back to the previous elements like this
      // $("#someid").findNext("div").remove().end().attr("id")
      // will now return "someid" 
      return this.pushStack( [ found ] );
    },  
    

    编辑2 使用jquery的$.grep要容易得多。这是新密码

       $.fn.findNextAll = function( selector ){
          var that = this[ 0 ],
              selection = $( selector ).get();
          return this.pushStack(
             // if there are no elements in the original selection return everything
             !that && selection ||
             $.grep( selection, function( n ){
                return [4,12,20].indexOf( that.compareDocumentPosition( n ) ) > -1
             // if you are looking for previous elements it should be [2,10,18]
             })
          );
       }
       $.fn.findNext = function( selector ){
          return this.pushStack( this.findNextAll( selector ).first() );
       }
    

    当压缩变量名时,这只会变成一个两行程序。

    编辑3 使用位运算,这个函数可能更快?

    $.fn.findNextAll = function( selector ){
      var that = this[ 0 ],
        selection = $( selector ).get();
      return this.pushStack(
        !that && selection || $.grep( selection, function(n){
           return that.compareDocumentPosition(n) & (1<<2);
           // if you are looking for previous elements it should be & (1<<1);
        })
      );
    }
    $.fn.findNext = function( selector ){
      return this.pushStack( this.findNextAll( selector ).first() );
    }
    
        3
  •  3
  •   Funka    16 年前

    我的解决方案将涉及到稍微调整标记以使jquery更简单。如果这不可能或不是一个有吸引力的答案,请忽略!

    我会用一个“家长”包装纸来包装你想做的事情…

    <div class="find-wrapper">
        <div><span id="click">hello</span></div>
        <div><p class="find">world></p></div>
    </div>
    

    现在,为了找到 find :

    $(function() {
        $('#click').click(function() {
            var $target = $(this).closest('.find-wrapper').find('.find');
            // do something with $target...
        });
    });
    

    这使您能够灵活地在我建议的包装器中使用任何类型的标记和层次结构,并且仍然能够可靠地找到目标。

    祝你好运!

        4
  •  0
  •   Martin Sturm    16 年前

    我认为解决这个问题的唯一方法是对当前元素之后的元素进行递归搜索。jquery提供的这个问题没有简单的解决方案。如果只想在父元素的同级中查找元素(如示例中的情况),则不需要执行递归搜索,但必须执行多个搜索。

    我创建了一个示例(实际上,它不是递归的),可以满足您的需要(我希望如此)。它选择当前单击元素之后的所有元素,并使其变为红色:

    <script type="text/javascript" charset="utf-8">
        $(function () {
            $('#click').click(function() {
                var parent = $(this);
                alert(parent);
                do {
                    $(parent).find('.find').css('background-color','red'); 
                    parent = $(parent).parent();
                } while(parent !== false);
            });
        });
    </script>
    
        5
  •  0
  •   dnagirl    16 年前

    以下表达式应该(除非语法错误!)查找包含 p.find 元素,然后找到它们 P.查找 元素,并将其颜色改为蓝色。

    $(this).parent().nextAll(":has(p.find)").find(".find").css('background-color','blue');
    

    当然,如果你的页面结构是这样的 P.查找 发生在完全不同的层次结构(例如祖父母的兄弟姐妹)中,它将不起作用。