Javascript: как определить, был ли объект node вставлен в документ/другой элемент еще
Я хотел бы определить, был ли добавлен/вставлен данный DOM node в другой node или он был свежим из document.createElement() или аналогичным и не был помещен в любом месте.
В большинстве браузеров работает только проверка parentNode.
if (!node.parentNode) {
// this node is not part of a larger document
}
Однако в Internet Explorer кажется, что новые элементы, даже сразу после того, как они были созданы с document.createElement(), уже имеют объект parentNode (типа DispHTMLDocument?).
Любой другой хороший кросс-браузер и надежный способ?
Изменить: похоже, что Internet Explorer неявно создает DocumentFragment (с nodeType из 11) и устанавливает это как свойство node parentNode.
Ответы
Ответ 1
Я нашел ответ на свой вопрос. Сожалею! Кажется, я делаю это много в последнее время.
Фрагменты документа имеют тип nodeType 11 и никогда не вставляются в документ, поэтому вы можете проверить его следующим образом:
if (!node.parentNode || node.parentNode.nodeType == 11) {
// this node is floating free
}
Вам нужен только фрагмент документа, когда вы вставляете более одного однорангового узла node. IE неявно создает один для всех вновь созданных узлов. В любом случае проверка nodeType для 11 работает.
Ответ 2
Я думаю, что даже без ошибок IE, проверка наличия parentNode может быть недостаточной. Например:
var d = document.createElement('div');
var s = document.createElement('span');
d.appendChild(s);
if (s.parentNode) {
// this will run though it not in the document
}
Если что-то находится в документе, то в конечном итоге одним из его предков станет сам документ. Попробуйте это и посмотрите, как это происходит:
function inDocument(node) {
var curr = node;
while (curr != null) {
curr = curr.parentNode;
if (curr == document) return true;
}
return false;
}
// usage:
// if (inDocument(myNode)) { .. }
Если вы хотите только проверить определенную глубину - то есть вы знаете, что ваши вновь созданные элементы не будут вложены дальше, чем IE Fragment, попробуйте следующее:
function inDocument(node, depth) {
depth = depth || 1000;
var curr = node;
while ((curr != document) && --depth) {
curr = curr.parentNode;
if (curr == null) return false;
}
return true;
}
inDocument(myNode, 2); // check only up to two deep.
inDocument(myNode); // check up to 1000 deep.
Ответ 3
Уровень DOM 3 представил метод compareDocumentPosition
для Node
, который дает позиционную информацию о том, как два узла связаны друг с другом. Одно из значений возврата DOCUMENT_POSITION_DISCONNECTED
означает, что узлы не связаны друг с другом. Можно использовать этот факт, чтобы проверить, не содержится ли node внутри другого node, используя:
Boolean(parent.compareDocumentPosition(descendant) & 16)
DOCUMENT_POSITION_DISCONNECTED = 0x01;
DOCUMENT_POSITION_PRECEDING = 0x02;
DOCUMENT_POSITION_FOLLOWING = 0x04;
DOCUMENT_POSITION_CONTAINS = 0x08;
DOCUMENT_POSITION_CONTAINED_BY = 0x10;
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
Google написал кросс-браузерную реализацию (я думаю, не упоминал об этом IE) функции contains
, которую можно найти в http://code.google.com/p/doctype-mirror/wiki/ArticleNodeContains. Вы можете использовать это для проверки того, является ли данный node потомком документа
.contains(document, someNode)
Ответ 4
В какой версии IE вы тестировали это:
if (!node.parentNode) {
// this node is not part of a larger document
}
возможно, с более старыми версиями IE, которые вы должны попробовать:
if (!node.parentElement) {
// this node is not part of a larger document
}
вместо.
Хотя на девятки вы получите → null < < причем оба подхода предусматривают, что верхний созданный элемент контейнера еще не разобран, что, в свою очередь, преобразуется в → false < < точно так, как вы этого хотели.