2010-06-22 2 views
5

Angesichts dieser Probe Auszeichnungs (eine zufällige Anzahl von Elementen zwischen .outer und .inner vorausgesetzt:jQuery Filterungs Selektors geschachtelte Elemente entfernen Musterabgleich

<div class="outer"> 
    <div> 
     <div> 
      <div class="inner"></div> 
     </div> 
    </div> 
</div> 

I jQuery einrichten können die äußeren und inneren divs als solche wählen:

$outer = $('.outer'); 
$inner = $outer.find('.inner') 

funktioniert.

Doch lassen Sie uns sagen, dass ich eine unbegrenzte Verschachtelung dieser Logik zulassen wollen, so kann ich thi s:

<div class="outer"> div a 
    <div class="inner"> div b 
     <div class="outer"> div c 
      <div class="inner"> div d </div> 
     </div> 
    </div> 
</div> 

In dieser Situation, wenn div ein über .outer Auswahl mag ich es passend mit nur div b. Mit anderen Worten, ich möchte Vorfahren eines verschachtelten .outer Vorfahren ausschließen.

Ich hätte gerne Partings von äußeren und inneren (s) enthalten innerhalb ihrer Verschachtelungsebene.

Ich hoffe, .filter() könnte es abziehen, aber kann nicht an einen Selektor denken, die universell für unbegrenzte verschachtelte Muster arbeiten würde. Ist es möglich, einen Filter zu verwenden? Oder vielleicht sogar ein direktes Selektormuster?

UPDATE:

Ich denke, so etwas wie dies funktionieren könnte, aber nicht sicher, wie kann man (oder, wenn es erlaubt) Referenz 'this' in einem Selektor:

$outer = $('.outer'); 
$inner = $outer.not('this .outer').find('.inner') 

UPDATE 2:

Ich sollte dies zunächst erwähnt haben: .inner wird immer ein Nachkomme von .outer sein, aber nicht unbedingt ein unmittelbares Kind.

UPDATE 3:

Hier einige Testproben von HTML, die verwendet werden könnten. In jedem Fall möchte ich in der Lage sein, die .outer-Datei auszuwählen und die .inner-Datei, die sie enthält, zwischen sich und der verschachtelten äußeren Seite zu paaren. Aus Gründen der Klarheit hinzugefügt I Namen zu jeder div (Außen-x-Paare mit Innen-x)

//sample 1 
<div class="outer"> outer-a 
    <div> 
     <div class="inner"> inner-a 
      <div class="outer"> inner-b 
       <div class="inner"> inner-b </div> 
      </div> 
     </div> 
    </div> 
    <div> 
     <div class="inner"> inner-a </div> 
    </div> 
</div> 

//sample 2 
<div class="outer"> outer-a 
     <div class="inner"> inner-a 
      <div class="outer"> inner-b 
       <div> 
        <div class="inner"> inner-b </div> 
       </div> 
      </div> 
     </div> 
</div> 

//sample 3 
<div class="outer"> outer-a 
     <div class="inner"> inner-a 
      <div class="outer"> inner-b 
       <div class="inner"> inner-b 
        <div class="outer"> outer-c 
         <div class="inner"> inner-c</div> 
        </div> 
       </div> 
      </div> 
     </div> 
</div> 

//bonus sample (we're trying to avoid this) 
<div class="outer"> outer-a 
     <div class="inner outer"> inner-a outer-b 
      <div class="inner"> inner-b </div> 
     </div> 
</div> 

UPDATE 4

Ich glaube, ich beenden einen ähnlichen Weg wie Gnarf hinunter auf. Ich bin damit gelandet:

var $outer = $('.outer'); 
var $inner = $outer.find('.inner').filter(function(){ 
    $(this).each(function(){ 
     return $(this).closest('.outer') == $outer; 
    });                 
}); 

Bin ich auf dem richtigen Weg dahin? Es funktioniert nicht, also nehme ich an, dass ich immer noch einen logischen Fehler habe.

+0

Dies macht keinen Sinn - auch wenn Sie das erste Nest passen und nur entfernen Sie das - seine Kinder würden sowieso entfernt werden – Matt

Antwort

11

Hier ist eine weitere Option. Angenommen, Sie haben die .outero, dies wählt alle inner s darunter:

o.find('.inner').not(o.find('.outer .inner')) 

Es sollte identisch zu gnarf Antwort arbeiten, aber ein bisschen einfacher.

Zuerst findet es alle inner s unter dieser outer.
Dann entfernen Sie alle inners, die Nachkommen anderer outers

Interaktive Arbeitsbeispiel: http://jsfiddle.net/Zb9gF/

Selector Leistung scheint mit dieser Methode viel besser zu sein als auch auf den .filter() Gegensatz: http://jsperf.com/selector-test-find-not

+0

aktualisiert Brilliant! Wie üblich ist die Antwort einfacher als der Pfad, den ich auf dem Weg nach unten führe. Ich habe mit der Syntax gekämpft, die benötigt wird, um ein zwischengespeichertes Objekt mit einem CSS-Selektor zu kombinieren, und die find() - Logik ist mir nicht aufgefallen. Vielen Dank! –

+0

Danke! Übrigens, die Frage ist sehr interessant und herausfordernd, es hat viel Arbeit gekostet, um zu dieser einfachen Linie zu gelangen ... – Kobi

+0

Schöne Optimierung, wünschte, ich hätte zuerst darüber nachgedacht :) - War nur mit der Nützlichkeit von ['.not()'] (http://api.jquery.com/not) gestern für [diese Antwort] (http://stackoverflow.com/questions/3089045). – gnarf

1
$('.outer').children('.inner'); 

dass jede inner wählen würde, die unmittelbar unter einem outer sitzt. Mir ist nicht klar, in welchem ​​Div du auswählen willst. Ist es a, b, c oder d? Etwas zu nennen, das in etwas namens Inneres verschachtelt ist, ergibt keinen Sinn. Vielleicht, wenn Sie ein konkreteres Beispiel geben könnten?

+0

+1 - Dies ist wahrscheinlich die beste Wette angenommen, dass die '.inner' ist immer ein direktes Kind der' .outer' und nicht verschachtelt eine andere Ebene nach unten ... – gnarf

+1

Entschuldigung für nicht das klarstellen. Das ist tatsächlich eine Variable. Inner wird ein Nachkomme sein, aber nicht notwendigerweise ein unmittelbares Kind. –

0

Sie könnten einige CSS-Magie:

$('.outer>.inner') 

shold Sie nur erste Ebene der .inner Elemente geben. :)

+1

Dieser Selektor wird beide '.inner's – gnarf

2

Wenn die .inner sind immer direkte Kinder von .outer s - children() ist wahrscheinlich die beste Wahl (jasongetsdown Antwort)

Wenn Sie brauchen etwas, das noch tiefer sieht man so etwas tun könnte:

var $outer = $('.outer').first(); // grab the first .outer 
$outer.find('.inner').filter(function() { 
    // only if the closest parent .outer is the same as the .outer we are looking in 
    return $(this).closest('.outer').get(0) == $outer.get(0); 
}).css('border','1px solid #000'); 

jsfiddle demo

+0

@gnarf ... Ich denke, das ist nahe, was ich auch dachte. Ich habe meinem Beitrag ein Update hinzugefügt, das auch eine Filterfunktion verwendet. Meins funktioniert nicht, also versuche deine Syntax als nächstes! –

+0

Übrigens +1 vor einer Stunde, nett. Ich bin mir ziemlich sicher, dass Sie Recht haben, das scheint die richtige Logik zu sein. – Kobi

1

Wenn übernehmen Sie alle richtig .inner auswählen möchten, die unter einem .outer ist, mit der Ausnahme wenn es eine .outer dazwischen, nach vielleicht funktionieren (ungetestet):

$('.outer:not(.inner):has(:not(.outer) .inner:not(.outer), > .inner:not(.outer))'); 

aktualisiert nach dem Test auf OP Beispiel HTML bei http://jsfiddle.net/cEwBT/1/

+0

Ihre Annahme ist richtig. Dieses Beispiel funktioniert jedoch nicht.Ich cache zuerst "äußere" und möchte dann alle Innenseiten finden, die kein Kind eines verschachtelten Äußeren sind. Der Haken ist, dass mein zwischengespeicherter äußerer * ist * ein .outer also würde sich selbst ausschließen. –

+0

Ich habe es jetzt nach einem Test über jsfiddle – azatoth

0

I frage mich, warum nicht .inner zuerst wählen, und dann closest.outer bekommen?

 
$inner = $('.inner'); 
$outer = $inner.closest('.outer'); 

falls einige innere Blöcke könnten überhaupt nicht innerhalb der äußeren Blöcke sein, verwenden Sie diese erste Zeile statt

$inner = $('.outer .inner');

+0

Die Frage ist hier in die andere Richtung. Wie kommt man zu seinen "inneren" divs? – Kobi

+0

sehen. meine Frage ist warum nicht andere Richtung gehen. Haben wir gegeben, funktioniert Kobis Antwort perfekt. aber wenn Sie nur alle Inners für alle äußeren bekommen müssen - vielleicht könnten Sie von vorne anfangen, um so zu sagen – vittore