Comment vérifier si un élément jQuery est dans le DOM?

147

Disons que je définis un élément

$foo = $('#foo');

et puis j'appelle

$foo.remove()

d'un événement. Ma question est la suivante: comment vérifier si $ foo a été supprimé du DOM ou non? J'ai trouvé que cela $foo.is(':hidden')fonctionne, mais cela reviendrait bien sûr aussi vrai si je appelais simplement $foo.hide().

Trevor Burnham
la source

Réponses:

238

Comme ça:

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

Cela fonctionnera toujours si l'un des parents de l'élément a été supprimé (auquel cas l'élément lui-même aura toujours un parent).

SLaks
la source
14
faire $foo.closest(document.documentElement)est plus rapide (si quelqu'un se soucie de jsperf.com/jquery-element-in-dom )
urraka
48
@PerroAzul: J'ai trouvé une alternative beaucoup plus rapide: jsperf.com/jquery-element-in-dom/2
SLaks
3
La performance était ma préoccupation immédiate avec cette méthode, merci d'avoir lié les benchmarks @SLaks. Il semble donc que ce $.contains(document.documentElement, $foo.get(0))soit le moyen le plus rapide.
Christof
10
Il existe un moyen purement DOM pour faire cela, qui est syntaxiquement plus lisible, et j'imagine très similaire en termes de performances:document.contains($foo[0])
Joel Cross
3
Tout ce discours sur la performance ...? Les benchmarks montrent une méthode prenant 15 microsecondes et une autre prenant 0,15 microsecondes. Mais vraiment, peu importe - vous ne remarquerez aucune différence à moins de le faire cent mille fois. Et tout cela pourrait changer si jQuery ou le moteur JavaScript est optimisé. Utilisez simplement la méthode qui vous convient le mieux et à quiconque doit maintenir votre code à l'avenir.
James
21

Que diriez-vous de faire ceci:

$element.parents('html').length > 0
Kushagra Gour
la source
Je pense que c'est beaucoup plus rapide
Trio Cheung
5

Je viens de réaliser une réponse en tapant ma question: Appeler

$foo.parent()

Si $f00a été supprimé du DOM, alors $foo.parent().length === 0. Sinon, sa longueur sera d'au moins 1.

[Modifier: ce n'est pas tout à fait correct, car un élément supprimé peut toujours avoir un parent; par exemple, si vous supprimez a <ul>, chacun de ses enfants <li>aura toujours un parent. Utilisez plutôt la réponse de SLaks.

Trevor Burnham
la source
2
... à moins que le nœud supprimé n'était pas un enfant unique
Álvaro González
@ Álvaro - Pourquoi est-ce important?
user113716
@patrick: J'ai raté quelque chose? Que pouvez-vous garantir si $ foo.parent (). Length est supérieur à zéro?
Álvaro González
@ Álvaro - l'OP teste pour s'assurer qu'il a $fooété supprimé du DOM. S'il a été supprimé avec succès, il n'aura plus d'élément parent. Par conséquent $foo.parent().length === 0, cela signifie que la suppression a réussi.
user113716
1
$ foo.closest ("body") serait un correctif pour cette technique
georgephillips
4

Comme je suis incapable de répondre en tant que commentaire (karma trop faible je suppose), voici une réponse complète. Le moyen le plus rapide est de dérouler facilement la vérification jQuery de la prise en charge du navigateur et de réduire au minimum les facteurs constants.

Comme vu aussi ici - http://jsperf.com/jquery-element-in-dom/28 - le code ressemblerait à ceci:

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);

Ceci est sémantiquement équivalent à jQuery.contains (document.documentElement, elt [0]).

Jaakko Salomaa
la source
3

La méthode la plus performante est probablement:

document.contains(node); // boolean

Cela fonctionne également avec jQuery:

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

Source de MDN

Remarque:

lxg
la source
Comment quelqu'un a-t-il encore regardé cette réponse? Excellente réponse +1 (j'ai suggéré une édition, merci)
Guilherme Nascimento
1

J'ai aimé cette approche. Pas de jQuery et pas de recherche DOM. Trouvez d'abord le parent supérieur (ancêtre). Ensuite, voyez si c'est le documentElement.

function ancestor(HTMLobj){
  while(HTMLobj.parentElement){HTMLobj=HTMLobj.parentElement}
  return HTMLobj;
}
function inTheDOM(obj){
  return ancestor(obj)===document.documentElement;
}
Bouton Brian
la source
1

au lieu d'itérer les parents, vous pouvez simplement obtenir le rectangle de délimitation qui est entièrement à zéro lorsque l'élément est détaché de dom

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

si vous souhaitez gérer la casse du bord d'un élément de largeur et de hauteur nulles à zéro en haut et à zéro à gauche, vous pouvez vérifier deux fois en itérant les parents jusqu'au document.

Erez Pilosof
la source
Bien que cet extrait de code puisse résoudre le problème, il n'explique pas pourquoi ni comment il répond à la question. Veuillez inclure une explication de votre code , car cela contribue vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondez à la question aux lecteurs à l'avenir, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. Flaggers / reviewers: pour les réponses de code uniquement comme celle-ci, votez contre, ne supprimez pas!
Luca Kiebel
Cela ne reconnaît-il pas également les éléments cachés comme «pas dans le DOM»? par exemple, un élément avec display: nonen'a pas de rectangle de délimitation non plus
Philipp
0

D'accord avec le commentaire de Perro. Cela peut également être fait comme ceci:

$foo.parents().last().is(document.documentElement);
Ian Bytchek
la source
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
la source
-1

Pourquoi pas simplement if( $('#foo').length === 0)...:?

stevematdavies
la source
@stevematdavies La question est "comment tester si un élément dans un objet jQuery donné est dans le DOM", et non "comment tester si un élément correspondant à une chaîne de sélecteur donnée est dans le DOM."
Trevor Burnham
@TrevorBurnham: en toute honnêteté, ré-interroger à l'aide du sélecteur utilisé pour créer $fooet vérifier si la ré-requête correspond à un élément, semble une solution viable au problème dans de nombreux scénarios. Cela peut même être plus rapide que certaines des autres solutions en raison de la façon dont jQuery et les navigateurs optimisent certains sélecteurs (par exemple, par ID).
Matt
@Matt $ foo pourrait être un élément en mémoire détaché du DOM, et il pourrait y avoir un élément avec un sélecteur correspondant dans le DOM. Les personnes à la recherche d'une réponse à cette question veulent probablement vérifier si elle est dans DOM ou non. Quelqu'un qui travaille dans ce genre de choses sait évidemment comment interroger DOM.
TJ
-1
if($foo.nodeType ){ element is node type}
tharo
la source