Suchen Sie nach der jQuery find (..) -Methode, die den aktuellen Knoten enthält

134

Die Traversal-Methode jQuery find (..) enthält nicht den aktuellen Knoten - sie beginnt mit den untergeordneten Knoten des aktuellen Knotens. Was ist der beste Weg, um eine Suchoperation aufzurufen, die den aktuellen Knoten in ihren Übereinstimmungsalgorithmus einbezieht? Beim Durchsehen der Dokumente springt mir nichts sofort heraus.

John K.
quelle

Antworten:

153

Für jQuery 1.8 und höher können Sie verwenden .addBack(). Es ist ein Selektor erforderlich, damit Sie das Ergebnis nicht filtern müssen:

object.find('selector').addBack('selector')

Vor jQuery 1.8 waren Sie festgefahren .andSelf()(jetzt veraltet und entfernt), was dann gefiltert werden musste:

object.find('selector').andSelf().filter('selector')
Robert
quelle
5
Ich habe dies als Plugin jquery.findIncludeSelf gebündelt, das bei bower registriert ist. Siehe github.com/ronen/jquery.findIncludeSelf
ronen
18
@ronen Eine zusätzliche Datei für etwas, das in einer Zeile erledigt werden kann? Danke, aber nein danke.
6
@ prc322 Eine zusätzliche Datei stört mich nicht für Bereitstellungen, bei denen das gesamte Javascript ohnehin in einer einzigen Datei gebündelt ist. Im Allgemeinen bevorzuge ich die Verwendung (getesteter) Bibliotheksmethoden auch für einfache Dinge, anstatt meinen Code mit Dingen zu überladen, die ich schwerer zu lesen finde und die mehr Möglichkeiten für Fehler bieten. Insbesondere in diesem Fall 'selector'macht meiner Meinung nach die Notwendigkeit, zweimal anzugeben, die Kapselung besonders wünschenswert. YMMV
ronen
Ok, ich bin vielleicht dick, aber du musst nicht 'selector'zweimal angeben (wie von @ronen erwähnt), könntest du nicht einfach object.parent().find('selector')??? - Davon abgesehen mag ich die Idee einer Bibliothek, die das für Sie erledigt.
Sam
8
@ circa1983 object.parent().find('selector')enthält Geschwister von objectund deren Nachkommen.
Robert
41

Sie können dies nicht direkt tun. Ich kann mir nur .andSelf()vorstellen .filter(), Folgendes zu verwenden und anzurufen :

$(selector).find(oSelector).andSelf().filter(oSelector)
//or...
$(selector).find('*').andSelf().filter(oSelector);

Nimmt leider .andSelf()keinen Selektor mit, was praktisch wäre.

Nick Craver
quelle
7
Sie haben der jquery-Seite sogar direkt nach Beantwortung dieser Frage einen Kommentar hinzugefügt. Api.jquery.com/andSelf/#comment-50124533 Nun, das ist Gründlichkeit. Nett! Ich habe meine Due Diligence durchgeführt und auch diese "gemocht".
John K
2
Der zweite wäre unglaublich langsam. Der erste ist einfach nur langsam.
Tgr
@Tgr - Ich bin nicht anderer Meinung, obwohl die erste nicht diese Show sein sollte, es sei denn, Sie haben es mit einer sehr großen Anzahl von Elementen zu tun . Wenn Sie nicht verketten müssen, können Sie das erneute Filtern dieser Elemente mit Sicherheit überspringen.
Nick Craver
3
Interessanterweise closest(..)enthält das aktuelle DOM-Element und den Baum nach oben, während alle Durchlaufmethoden nach unten wie find(..)usw. nicht mit dem aktuellen Element übereinstimmen. Es ist, als ob das jQuery-Team diese absichtlich ohne Überlappung implementiert hat, wenn beide Vorgänge zusammen für eine vollständige vertikale Suche verwendet wurden.
John K
17
Beachten Sie, dass .andSelf () ab Version 1.8 veraltet und durch .addBack () ersetzt wurde, das einen Selektor als Argument verwendet. Siehe api.jquery.com/addBack
kkara
9

Definieren

$.fn.findSelf = function(selector) {
    var result = this.find(selector);
    this.each(function() {
        if ($(this).is(selector)) {
            result.add($(this));
        }
    });
    return result;
};

dann benutze

$.findSelf(selector);

anstatt

$find(selector);

Leider verfügt jQuery nicht über diese integrierte Funktion. Wirklich seltsam für so viele Jahre der Entwicklung. Meine AJAX-Handler wurden aufgrund der Funktionsweise von .find () nicht auf einige Top-Elemente angewendet.

Dmitriy Sintsov
quelle
Das ist fehlerhaft. Es fügt alles von "Selbst" hinzu, auch wenn nur eines von ihnen übereinstimmt ... - Ein Grund für diesen Fehler ist eine beschissen benannte jQuery-Methode ...
Robert Siemer
Ich habe versucht, den von Ihnen gemeldeten Fehler zu beheben. Funktioniert es jetzt richtig?
Dmitriy Sintsov
Die meisten anderen Antworten werden filter()dort verwendet, was sinnvoller ist.
Robert Siemer
5
$('selector').find('otherSelector').add($('selector').filter('otherSelector'))

Sie können $('selector')zur Beschleunigung in einer Variablen speichern. Sie können sogar eine benutzerdefinierte Funktion dafür schreiben, wenn Sie sie häufig benötigen:

$.fn.andFind = function(expr) {
  return this.find(expr).add(this.filter(expr));
};

$('selector').andFind('otherSelector')
Tgr
quelle
Dies funktioniert nur , wenn Sie beginnen mit einer Wahl obwohl, die möglicherweise nicht der Fall sein. Es ist auch falsch, es wäre $('selector').find('otherSelector').add($('otherSelector')), was Sie jetzt haben, ist gleichbedeutend mit .andSelf(). Schließlich .andFind()filtert das nicht basierend auf dem Ausdruck, den Sie benötigen würden .add($(this).filter(expr)):)
Nick Craver
@ Nick Craver: Ja, ich habe den Filterteil vergessen, der jetzt behoben wurde. Es spielt keine Rolle, ob $('selector')es durch eine andere Methode zum Abrufen eines jQuery-Objekts ersetzt wird (wenn Sie damit gemeint haben, nicht mit einem Selektor zu beginnen), add()kann alles genauso gut wie $()möglich verarbeiten.
Tgr
Mein Punkt war, dass Ihr $('selector')möglicherweise $('selector').children('filter').closest('.class').last()... es sich möglicherweise in einer Kette befindet und Sie keine Ahnung haben, um welches Objekt es sich handelt.
Daher
Ich verstehe immer noch nicht, warum das ein Problem wäre. thisist das jQuery-Objekt, für das ein Plugin aufgerufen wurde. Es könnte genauso gut das Ergebnis einer Anrufkette sein.
Tgr
5

Die akzeptierte Antwort ist sehr ineffizient und filtert den Satz von Elementen, die bereits übereinstimmen.

//find descendants that match the selector
var $selection = $context.find(selector);
//filter the parent/context based on the selector and add it
$selection = $selection.add($context.filter(selector);
erikrestificar
quelle
3

Wenn Sie möchten, dass die Verkettung ordnungsgemäß funktioniert, verwenden Sie das folgende Snippet.

$.fn.findBack = function(expr) {
    var r = this.find(expr);
    if (this.is(expr)) r = r.add(this);
    return this.pushStack(r);
};

Nach dem Aufruf der Endfunktion wird das Element #foo zurückgegeben.

$('#foo')
    .findBack('.red')
        .css('color', 'red')
    .end()
    .removeAttr('id');

Ohne zusätzliche Plugins zu definieren, bleiben Sie dabei.

$('#foo')
    .find('.red')
        .addBack('.red')
            .css('color', 'red')
        .end()
    .end()
    .removeAttr('id');
SeregPie
quelle
Ah, nein ... Wenn thismehr als ein Element this.is()bereits erfüllt ist, wenn nur eines von ihnen übereinstimmt.
Robert Siemer
3

Wenn Sie genau ein Element suchen , entweder das aktuelle Element oder eines darin, können Sie Folgendes verwenden:

result = elem.is(selector) ? elem : elem.find(selector);

Wenn Sie nach mehreren Elementen suchen , können Sie Folgendes verwenden:

result = elem.filter(selector).add(elem.find(selector));

Die Verwendung von andSelf/andBack ist ziemlich selten, nicht sicher warum. Vielleicht wegen der Leistungsprobleme, die einige Leute vor mir erwähnt haben.

(Mir ist jetzt aufgefallen, dass Tgr diese zweite Lösung bereits gegeben hat)

Oriadam
quelle
2

Ich weiß, dass dies eine alte Frage ist, aber es gibt einen korrekteren Weg. Wenn die Reihenfolge wichtig ist, zum Beispiel wenn Sie mit einem Selektor wie übereinstimmen :first, habe ich eine kleine Funktion geschrieben, die genau das gleiche Ergebnis zurückgibt, als ob sie find()tatsächlich den aktuellen Satz von Elementen enthält:

$.fn.findAll = function(selector) {
  var $result = $();

  for(var i = 0; i < this.length; i++) {
    $result = $result.add(this.eq(i).filter(selector));
    $result = $result.add(this.eq(i).find(selector));
  }

  return $result.filter(selector);
};

Es wird keineswegs effizient sein, aber es ist das Beste, was ich mir ausgedacht habe, um die richtige Ordnung aufrechtzuerhalten.

Justin Warkentin
quelle
1

Ich denke andSelfist was du willst:

obj.find(selector).andSelf()

Beachten Sie, dass dadurch immer der aktuelle Knoten hinzugefügt wird, unabhängig davon, ob er mit dem Selektor übereinstimmt oder nicht.

Interjay
quelle
1

Wenn Sie streng nach den aktuellen Knoten suchen, tun Sie dies einfach

$(html).filter('selector')
mikewasmike
quelle
0

Ich habe versucht, eine Lösung zu finden , die sich nicht wiederholt (dh nicht zweimal denselben Selektor eingibt).

Und diese winzige jQuery-Erweiterung macht es:

jQuery.fn.findWithSelf = function(...args) {
  return this.pushStack(this.find(...args).add(this.filter(...args)));
};

Es kombiniert find()(nur Nachkommen) mit filter()(nur aktuelle Menge) und unterstützt alle Argumente, die beide essen. Das pushStack()erlaubt.end() , wie erwartet zu arbeiten.

Verwenden Sie wie folgt:

$(element).findWithSelf('.target')
Robert Siemer
quelle
-2

Hier ist die richtige (aber traurige) Wahrheit:

$(selector).parent().find(oSelector).filter($(selector).find('*'))

http://jsfiddle.net/SergeJcqmn/MeQb8/2/

Serge
quelle
funktioniert jedoch nicht mit getrennten Knoten (und dem Dokument selbst).
John Dvorak
2
Äh, nein, dies wird $(selector)sich in allen Fällen aus dem Set entfernen .
John Dvorak