Как проверить, есть ли элемент JQuery в DOM?

147

Допустим, я определяю элемент

$foo = $('#foo');

а потом я звоню

$foo.remove()

с какого-то события. У меня вопрос, как я могу проверить, был ли $ foo удален из DOM или нет? Я обнаружил, что это $foo.is(':hidden')работает, но это, конечно, также вернет истину, если я просто позвоню $foo.hide().

Тревор Бернхэм
источник

Ответы:

238

Как это:

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

Это все равно будет работать, если один из родителей элемента был удален (в этом случае у самого элемента все еще будет родитель).

SLaks
источник
14
делать $foo.closest(document.documentElement)быстрее (если кого-то волнует jsperf.com/jquery-element-in-dom )
urraka
48
@PerroAzul: я нашел намного более быструю альтернативу: jsperf.com/jquery-element-in-dom/2
SLaks
3
Производительность была моей непосредственной заботой об этом методе, спасибо за привязку тестов @SLaks. Так что, похоже, $.contains(document.documentElement, $foo.get(0))это самый быстрый способ.
Христоф
10
Есть способ чистого DOM сделать это, который синтаксически более читабелен, и я думаю, что он очень похож с точки зрения производительности:document.contains($foo[0])
Джоэл Кросс
3
Все эти разговоры о производительности ...? Тесты показывают, что один метод занимает 15 микросекунд, а другой - 0,15 микросекунд. Но на самом деле, кого это волнует - вы не заметите никакой разницы, если не сделаете это сто тысяч раз. И все это может измениться, если jQuery или движок JavaScript будут оптимизированы. Просто используйте любой метод, который лучше читается для вас и для тех, кто должен будет поддерживать ваш код в будущем.
Джеймс
21

Как насчет этого:

$element.parents('html').length > 0
Кушагра Гур
источник
Я думаю, что это намного быстрее
Трио Чунг
5

Я только что понял ответ, когда набирал вопрос: Позвони

$foo.parent()

Если $f00был удален из DOM, то $foo.parent().length === 0. В противном случае его длина будет не менее 1.

[Редактировать: это не совсем правильно, потому что удаленный элемент все еще может иметь родителя; например, если вы удалите a <ul>, у каждого из его дочерних элементов <li>все равно будет родитель. Вместо этого используйте ответ SLaks.

Тревор Бернхэм
источник
2
... если только удаленный узел не был единственным ребенком
Альваро Гонсалес
@ Альваро - Почему это важно?
user113716
@patrick: Я что-то пропустил? Что вы можете убедиться, если $ foo.parent (). Length больше нуля?
Альваро Гонсалес
@ Альваро - ОП тестирует, чтобы убедиться, что он $fooбыл удален из DOM. Если он был успешно удален, у него больше не будет родительского элемента. Следовательно, $foo.parent().length === 0означает, что удаление было успешным.
user113716
1
$ foo.closest ("body") будет исправлением для этой техники
georgephillips
4

Поскольку я не могу ответить как комментарий (я думаю, слишком низкая карма), вот полный ответ. Самый быстрый способ - это просто развернуть проверку jQuery для поддержки браузера и сократить постоянные факторы до минимума.

Как видно также здесь - http://jsperf.com/jquery-element-in-dom/28 - код будет выглядеть так:

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

Это семантически эквивалентно jQuery.contains (document.documentElement, elt [0]).

Яакко Саломаа
источник
3

Вероятно, наиболее эффективный способ:

document.contains(node); // boolean

Это также работает с jQuery:

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

Источник из МДН

Примечание:

LXG
источник
Как кто-нибудь смотрел на этот ответ еще? Отличный ответ +1 (я предложил издание, спасибо)
Гильерме Насименто
1

Мне понравился этот подход. Нет JQuery и DOM поиска. Сначала найдите верхнего родителя (предка). Затем посмотрите, является ли это documentElement.

function ancestor(HTMLobj){
  while(HTMLobj.parentElement){HTMLobj=HTMLobj.parentElement}
  return HTMLobj;
}
function inTheDOM(obj){
  return ancestor(obj)===document.documentElement;
}
Брайан Баттон
источник
1

вместо того, чтобы перебирать родителей, вы можете просто получить ограничивающий прямоугольник, который равен нулю, когда элемент отсоединен от dom

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

если вы хотите обработать крайний край нулевого элемента ширины и высоты с нуля сверху и с нуля слева, вы можете дважды проверить, перебирая родителей до document.body

Эрез Пилософ
источник
Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста, включите объяснение вашего кода , так как это действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код. Флаггеры / рецензенты: для ответов только с кодом, таких как этот, downvote, не удаляйте!
Лука Кибель
Разве это также не распознает скрытые элементы как «не в DOM»? например, элемент с display: noneне имеет boundingRect либо
Филипп
0

Согласитесь с комментарием Перро. Это также можно сделать так:

$foo.parents().last().is(document.documentElement);
Ян Бытчек
источник
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;
};
Родриго Зофф
источник
-1

Почему не просто if( $('#foo').length === 0)...:?

stevematdavies
источник
@stevematdavies Вопрос заключается в том, «как проверить, находится ли элемент в данном объекте jQuery в DOM», а не «как проверить, находится ли элемент, соответствующий заданной строке селектора, в DOM».
Тревор Бёрнхем
@TrevorBurnham: по правде говоря, повторный запрос с использованием селектора, который использовался для создания $foo, и проверка соответствия повторного запроса какому-либо элементу, кажется жизнеспособным решением проблемы во многих сценариях. Это может быть даже быстрее, чем некоторые другие решения, из-за того, как jQuery и браузеры оптимизируют определенные селекторы (например, по идентификатору).
Мэтт
@Matt $ foo может быть элементом в памяти, отделенным от DOM, и в DOM может быть элемент с соответствующим селектором. Люди, которые ищут ответ на этот вопрос, вероятно, хотят проверить, находится ли он в DOM или нет. Кто-то, работающий в подобных вещах, очевидно, знает, как запрашивать DOM.
TJ