¿Cómo verifico si un elemento jQuery está en el DOM?

147

Digamos que defino un elemento

$foo = $('#foo');

y luego llamo

$foo.remove()

de algún evento Mi pregunta es, ¿cómo verifico si $ foo se ha eliminado del DOM o no? Descubrí que $foo.is(':hidden')funciona, pero eso también sería cierto si simplemente llamara $foo.hide().

Trevor Burnham
fuente

Respuestas:

238

Me gusta esto:

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

Esto seguirá funcionando si se eliminó uno de los elementos primarios del elemento (en cuyo caso, el elemento mismo seguirá teniendo un elemento primario).

SLaks
fuente
14
hacer $foo.closest(document.documentElement)es más rápido (si a alguien le importa jsperf.com/jquery-element-in-dom )
urraka
48
@PerroAzul: Encontré una alternativa mucho más rápida: jsperf.com/jquery-element-in-dom/2
SLaks
3
El rendimiento fue mi preocupación inmediata con este método, gracias por vincular los puntos de referencia @SLaks. Parece que $.contains(document.documentElement, $foo.get(0))es la forma más rápida.
Christof
10
Hay una manera pura de DOM para hacer esto, que es sintácticamente más legible, e imagino que es muy similar en términos de rendimiento:document.contains($foo[0])
Joel Cross
3
Toda esta charla de rendimiento ...? Los puntos de referencia muestran un método que toma 15 microsegundos y otro que toma 0,15 microsegundos. Pero realmente, a quién le importa: no notará ninguna diferencia a menos que lo haga cien mil veces. Y todo podría cambiar si jQuery o el motor de JavaScript se optimiza. Simplemente use el método que le resulte mejor a usted y a quien tenga que mantener su código en el futuro.
James
21

¿Qué tal hacer esto?

$element.parents('html').length > 0
Kushagra Gour
fuente
Creo que esto es mucho más rápido
Trio Cheung
5

Acabo de darme una respuesta mientras escribía mi pregunta: Llamar

$foo.parent()

Si $f00se ha eliminado del DOM, entonces $foo.parent().length === 0. De lo contrario, su longitud será al menos 1.

[Editar: Esto no es del todo correcto, porque un elemento eliminado aún puede tener un padre; por ejemplo, si elimina un <ul>, cada uno de sus hijos <li>seguirá teniendo un padre. Utilice la respuesta de SLaks en su lugar.

Trevor Burnham
fuente
2
... a menos que el nodo eliminado no sea hijo único
Álvaro González
@ Álvaro - ¿Por qué eso importaría?
user113716
@patrick: ¿Me perdí algo? ¿Qué puede asegurar si $ foo.parent (). Length es mayor que cero?
Álvaro González
@ Álvaro: el OP está probando para asegurarse de que $foose haya eliminado del DOM. Si se eliminó con éxito, ya no tendrá un elemento padre. Por $foo.parent().length === 0lo tanto, significa que la eliminación fue exitosa.
user113716
1
$ foo.closest ("cuerpo") sería una solución para esta técnica
georgephillips
4

Como no puedo responder como un comentario (supongo que el karma es demasiado bajo), aquí hay una respuesta completa. La forma más rápida es desenrollar fácilmente la comprobación de jQuery para el soporte del navegador y reducir al mínimo los factores constantes.

Como se ve también aquí: http://jsperf.com/jquery-element-in-dom/28 , el código se vería así:

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

Esto es semánticamente equivalente a jQuery.contains (document.documentElement, elt [0]).

Jaakko Salomaa
fuente
3

Probablemente la forma más performativa es:

document.contains(node); // boolean

Esto también funciona con jQuery:

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

Fuente de MDN

Nota:

lxg
fuente
¿Cómo ha visto alguien esta respuesta todavía? Gran respuesta +1 (sugerí una edición, gracias)
Guilherme Nascimento
1

Me gustó este enfoque. Sin jQuery y sin búsqueda DOM. Primero encuentre el padre principal (ancestro). Luego vea si ese es el documentElement.

function ancestor(HTMLobj){
  while(HTMLobj.parentElement){HTMLobj=HTMLobj.parentElement}
  return HTMLobj;
}
function inTheDOM(obj){
  return ancestor(obj)===document.documentElement;
}
Brian Button
fuente
1

en lugar de iterar padres, puede obtener el rect de límite que es todo ceros cuando el elemento se separa de dom

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

si desea manejar el caso de borde de un elemento de ancho y altura cero en la parte superior cero y cero izquierda, puede verificar dos veces iterando los padres hasta el documento.

Erez Pilosof
fuente
Si bien este fragmento de código puede resolver el problema, no explica por qué o cómo responde la pregunta. Por favor, incluya una explicación de su código , como que realmente ayuda a mejorar la calidad de su puesto. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no conocer los motivos de su sugerencia de código. Señaladores / revisores: para respuestas de solo código como esta, ¡voto negativo, no elimine!
Luca Kiebel
¿No reconoce esto también elementos ocultos como "no en DOM"? por ejemplo, un elemento con display: noneno tiene límiteRect tampoco
Philipp
0

De acuerdo con el comentario de Perro. También se puede hacer así:

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

¿Por qué no solo if( $('#foo').length === 0)...:?

stevematdavies
fuente
@stevematdavies La pregunta es "cómo probar si un elemento en un objeto jQuery dado está en el DOM", no "cómo probar si un elemento que coincide con una cadena selectora dada está en el DOM".
Trevor Burnham
@TrevorBurnham: para ser justos, volver a consultar utilizando el selector que se utilizó para crear $fooy verificar si la nueva consulta coincidía con algún elemento, parece una solución viable al problema en muchos escenarios. Puede ser incluso más rápido que algunas de las otras soluciones debido a cómo jQuery y los navegadores optimizan ciertos selectores (como por ID).
Matt
@Matt $ foo podría ser un elemento en la memoria separado de DOM, y podría haber un elemento con un selector coincidente en DOM. Las personas que buscan una respuesta a esta pregunta probablemente quieran verificar si está en DOM o no. Alguien que trabaja en cosas como esa obviamente sabe cómo consultar DOM.
TJ
-1
if($foo.nodeType ){ element is node type}
tharo
fuente