2009-12-01 5 views
16

Следующие, prev, nextAll и prevВсе методы очень полезны, но не если элементы, которые вы пытаетесь найти, не находятся в одном и том же родительском элементе. То, что я хочу сделать что-то вроде этого:jQuery find next/prev элементы определенного класса, но не обязательно siblings

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

Когда срок с идентификатором click нажат, я хочу, чтобы соответствовать следующему элементу с классом find, который в данном случае не является родственным из клики элемент next() или nextAll() не будет работать.

+0

возможно дубликат [JQuery найти все предыдущие элементы, которые соответствуют выражение] (http://stackoverflow.com/questions/322912/jquery-to-find-all-previous-elements-that-match- an-expression) – sachleen

ответ

8

я работал над этой проблемой сам сегодня, вот что я придумал:

/** 
* 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'); 

Я сомневаюсь, что это будет хорошо работать на крупных структур, но здесь это :)

+0

Не работает, если элемент, который вы хотите выбрать, является братом. И он объявляет глобальную переменную «сено». –

+1

И кто бы это изменил, чтобы найти Предыдущий? – Relm

+0

очень хорошо написано! –

0

Я думаю, что единственный способ решить эту проблему - сделать рекурсивный поиск по элементам после текущего элемента. Нет простого решения этой проблемы, предоставляемой 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> 
0

Следующее выражение следует (за исключением синтаксических ошибок!) Найти все братские родителя, которые содержат p.find элемент, а затем найти эти p.find элементы и изменения их цвет - синий.

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

Конечно, если ваша страница структура такова, что p.find происходит в совершенно другом уровне иерархии (родственный прародителя, например), он не будет работать.

3

Мое решение включает в себя корректировку разметки, чтобы сделать 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... 
    }); 
}); 

Это дает вам гибкость, чтобы иметь все, что вид разметки и иерархии, которые вы хотели бы использовать в оболочке, которую я предложил, и все еще надежно находить вашу цель.

Удачи вам!

13

Попробуйте это. Он будет отмечать ваш элемент, создать набор элементов, соответствующих вашему селектору, и собрать все элементы из набора, следующего за вашим элементом.

$.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 
} 

EDIT

гораздо более простое решение с использованием jquerys индексного метода. элемент вызова метода из потребности быть выбираются тем же селектор, хотя

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

освободить функцию от этого гандикапа, мы могли бы Youse браузеров собственных 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 ]); 
}, 

EDIT 2 это намного проще с использованием $ .grep jQuery. вот новый код

$.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()); 
} 
+0

Один из недостатков, о котором я думал, состоит в том, что элемент, который вы вызываете findNext from, должен выбираться одним и тем же селектором, иначе он будет просто перебирать все, не найдя выделенный элемент. – lordvlad

+0

Спасибо, я посмотрел повсюду, и никто другой не ответил на случай, не относящийся к брату, как лаконично, как вы. –

+0

Спасибо за вашу работу. С очень большими табличными документами Edit 2 ускорил то, что я пытался сделать на порядки! – David