Jak sprawdzić, czy element jQuery znajduje się w DOM?

147

Powiedzmy, że definiuję element

$foo = $('#foo');

a potem dzwonię

$foo.remove()

z jakiegoś wydarzenia. Moje pytanie brzmi, jak sprawdzić, czy $ foo zostało usunięte z DOM, czy nie? Przekonałem się, że to $foo.is(':hidden')działa, ale to oczywiście zwróci prawdę, gdybym tylko zadzwonił $foo.hide().

Trevor Burnham
źródło

Odpowiedzi:

238

Lubię to:

if (!jQuery.contains(document, $foo[0])) {
    //Element is detached
}

Będzie to nadal działać, jeśli jeden z elementów nadrzędnych elementu został usunięty (w takim przypadku sam element nadal będzie miał element nadrzędny).

SLaks
źródło
14
robienie $foo.closest(document.documentElement)jest szybsze (jeśli kogoś to obchodzi jsperf.com/jquery-element-in-dom )
urraka
48
@PerroAzul: Znalazłem znacznie szybszą alternatywę: jsperf.com/jquery-element-in-dom/2
SLaks
3
Wydajność była moim bezpośrednim zmartwieniem w przypadku tej metody, dzięki za połączenie testów porównawczych @SLaks. Więc wygląda na to, że $.contains(document.documentElement, $foo.get(0))to najszybszy sposób.
Christof
10
Jest na to sposób oparty na modelu DOM, który jest bardziej czytelny pod względem składni i wyobrażam sobie bardzo podobny pod względem wydajności:document.contains($foo[0])
Joel Cross
3
Cała ta rozmowa o wydajności ...? Testy porównawcze pokazują, że jedna metoda zajmuje 15 mikrosekund, a inna 0,15 mikrosekundy. Ale tak naprawdę, kogo to obchodzi - nie zauważysz żadnej różnicy, chyba że zrobisz to sto tysięcy razy. I wszystko może się zmienić, jeśli jQuery lub silnik JavaScript zostanie zoptymalizowany. Po prostu użyj dowolnej metody, która będzie lepiej czytać Tobie i każdemu, kto będzie musiał utrzymywać Twój kod w przyszłości.
James,
21

Co powiesz na to:

$element.parents('html').length > 0
Kushagra Gour
źródło
Myślę, że to jest dużo szybsze
Trio Cheung,
5

Właśnie zrozumiałem odpowiedź, kiedy pisałem swoje pytanie: Zadzwoń

$foo.parent()

Jeśli $f00został usunięty z DOM, to $foo.parent().length === 0. W przeciwnym razie jego długość będzie wynosić co najmniej 1.

[Edycja: Nie jest to całkowicie poprawne, ponieważ usunięty element może nadal mieć rodzica; na przykład, jeśli usuniesz a <ul>, każde z jego dzieci <li>nadal będzie miało rodzica. Zamiast tego użyj odpowiedzi SLaków.

Trevor Burnham
źródło
2
... chyba że usunięty węzeł nie był jedynakiem
Álvaro González
@ Álvaro - Dlaczego miałoby to znaczenie?
user113716
@patrick: Czy coś przegapiłem? Co możesz zapewnić, jeśli długość $ foo.parent (). Jest większa od zera?
Álvaro González
@ Álvaro - OP przeprowadza testy, aby upewnić się, że $foozostał usunięty z DOM. Jeśli zostanie pomyślnie usunięty, nie będzie już miał elementu nadrzędnego. Oznacza $foo.parent().length === 0to, że usunięcie powiodło się.
user113716
1
$ foo.closest ("body") byłoby poprawką dla tej techniki
georgephillips
4

Ponieważ nie mogę odpowiedzieć jako komentarz (wydaje mi się, że jest to zbyt niska karma), oto pełna odpowiedź. Najszybszym sposobem jest łatwe rozwinięcie sprawdzania jQuery pod kątem obsługi przeglądarki i ograniczenie stałych współczynników do minimum.

Jak widać również tutaj - http://jsperf.com/jquery-element-in-dom/28 - kod wyglądałby tak:

var isElementInDOM = (function($) {
  var docElt = document.documentElement, find,
      contains = docElt.contains ?
        function(elt) { return docElt.contains(elt); } :

        docElt.compareDocumentPosition ?
          function(elt) {
            return docElt.compareDocumentPosition(elt) & 16;
          } :
          ((find = function(elt) {
              return elt && (elt == docElt || find(elt.parentNode));
           }), function(elt) { return find(elt); });

  return function(elt) {
    return !!(elt && ((elt = elt.parent) == docElt || contains(elt)));
  };
})(jQuery);

Jest to semantyczne odpowiednik jQuery.contains (document.documentElement, elt [0]).

Jaakko Salomaa
źródło
3

Prawdopodobnie najbardziej performatywny sposób to:

document.contains(node); // boolean

Działa to również z jQuery:

document.contains($element[0]); // var $element = $("#some-element")
document.contains(this[0]); // in contexts like $.each(), `this` is the jQ object

Źródło z MDN

Uwaga:

lxg
źródło
Jak ktoś jeszcze spojrzał na tę odpowiedź? Świetna odpowiedź +1 (zaproponowałem wydanie, dzięki)
Guilherme Nascimento
1

Podobało mi się to podejście. Bez jQuery i bez wyszukiwania DOM. Najpierw znajdź najwyższego rodzica (przodka). Następnie sprawdź, czy to jest documentElement.

function ancestor(HTMLobj){
  while(HTMLobj.parentElement){HTMLobj=HTMLobj.parentElement}
  return HTMLobj;
}
function inTheDOM(obj){
  return ancestor(obj)===document.documentElement;
}
Brian Button
źródło
1

zamiast iterować rodziców, możesz po prostu uzyskać prostokąt ograniczający, który składa się z samych zer, gdy element jest odłączany od domeny

function isInDOM(element) {
    var rect=element.getBoundingClientRect();
    return (rect.top || rect.bottom || rect.height || rect.width)?true:false;
}

jeśli chcesz obsłużyć skrajny przypadek elementu o zerowej szerokości i wysokości na zero na górze i zero po lewej stronie, możesz dwukrotnie sprawdzić, iterując rodziców aż do dokumentu. body

Erez Pilosof
źródło
Chociaż ten fragment kodu może rozwiązać problem, nie wyjaśnia, dlaczego ani jak odpowiada na pytanie. Dołącz wyjaśnienie swojego kodu , ponieważ naprawdę pomaga to poprawić jakość Twojego postu. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod. Osoby zgłaszające / recenzujące: w przypadku odpowiedzi zawierających tylko kod, takich jak ta, głosuj przeciw, nie usuwaj!
Luca Kiebel
Czy to również nie rozpoznaje ukrytych elementów jako „nie w DOM”? np. element display: nonebez ograniczeńRect
Filip
0

Zgadzam się z komentarzem Perro. Można to również zrobić w ten sposób:

$foo.parents().last().is(document.documentElement);
Ian Bytchek
źródło
0
jQuery.fn.isInDOM = function () {
   if (this.length == 1) {
      var element = this.get(0);
      var rect = element.getBoundingClientRect();
      if (rect.top + rect.bottom + rect.width + rect.height + rect.left + rect.right == 0)
         return false;
      return true;
   }
   return false;
};
Rodrigo Zoff
źródło
-1

Dlaczego nie tylko if( $('#foo').length === 0)...:?

stevematdavies
źródło
@stevematdavies Pytanie brzmi „jak sprawdzić, czy element w danym obiekcie jQuery jest w DOM”, a nie „jak sprawdzić, czy element pasujący do danego ciągu selektora znajduje się w DOM”.
Trevor Burnham
@TrevorBurnham: z całą uczciwością ponowne zapytanie za pomocą selektora, który został użyty do utworzenia $fooi sprawdzenie, czy ponowne zapytanie pasowało do dowolnego elementu, wydaje się realnym rozwiązaniem problemu w wielu scenariuszach. Może to być nawet szybsze niż niektóre inne rozwiązania ze względu na to, jak zarówno jQuery, jak i przeglądarki optymalizują niektóre selektory (na przykład według identyfikatora).
Matt
@Matt $ foo może być elementem w pamięci odłączonym od DOM, a może tam być element z pasującym selektorem w DOM. Osoby szukające odpowiedzi na to pytanie prawdopodobnie chcą sprawdzić, czy jest w DOM, czy nie. Ktoś, kto zajmuje się takimi rzeczami, oczywiście wie, jak wysyłać zapytania do DOM.
TJ
-1
if($foo.nodeType ){ element is node type}
tharo
źródło