我怎样才能确定一个dynamic创build的DOM元素是否已经添加到DOM?
根据规范 ,只有BODY
和FRAMESET
元素提供了一个“onload”事件来附加,但我想知道什么时候dynamic创build的DOM元素已经被添加到DOM中的JavaScript。
我目前使用的超天真的启发式,其工作如下:
- 遍历元素的parentNode属性,直到find最终的祖先(即parentNode.parentNode.parentNode.etc,直到parentNode为null)
- 如果最终的祖先有一个定义的,非null的身体属性
- 假设有问题的元素是dom的一部分
- 其他
- 在100毫秒内再次重复这些步骤
我所追求的是要么证实我所做的事情是足够的(再次,它在IE7和FF3中都有效),要么是更好的解决scheme,无论出于何种原因,我都完全忘记了; 也许其他属性我应该检查,等等
编辑:我想要一个浏览器不可知的方式做到这一点,我不住在一个浏览器的世界,不幸的是, 说,浏览器的具体信息是赞赏,但请注意哪个浏览器,你知道它的工作。谢谢!
更新:对于任何有兴趣的人,这里是我最终使用的实现:
function isInDOMTree(node) { // If the farthest-back ancestor of our node has a "body" // property (that node would be the document itself), // we assume it is in the page's DOM tree. return !!(findUltimateAncestor(node).body); } function findUltimateAncestor(node) { // Walk up the DOM tree until we are at the top (parentNode // will return null at that point). // NOTE: this will return the same node that was passed in // if it has no ancestors. var ancestor = node; while(ancestor.parentNode) { ancestor = ancestor.parentNode; } return ancestor; }
我想这样做的原因是提供一种合成DOM元素的onload
事件的方法。 这是这个函数(尽pipe我使用的是稍微不同的,因为我和MochiKit一起使用):
function executeOnLoad(node, func) { // This function will check, every tenth of a second, to see if // our element is a part of the DOM tree - as soon as we know // that it is, we execute the provided function. if(isInDOMTree(node)) { func(); } else { setTimeout(function() { executeOnLoad(node, func); }, 100); } }
举个例子,这个设置可以使用如下:
var mySpan = document.createElement("span"); mySpan.innerHTML = "Hello world!"; executeOnLoad(mySpan, function(node) { alert('Added to DOM tree. ' + node.innerHTML); }); // now, at some point later in code, this // node would be appended to the document document.body.appendChild(mySpan); // sometime after this is executed, but no more than 100 ms after, // the anonymous function I passed to executeOnLoad() would execute
希望对某人有用。
注意:我最终使用这个解决scheme而不是Darryl的答案是因为getElementById技术只适用于你在同一个文档中; 我在页面上有一些iframe,页面之间以一些复杂的方式进行通信 – 当我尝试这样做时,问题是无法find元素,因为它是不同于它正在执行的代码的一部分。
最直接的答案是利用由Chrome,Firefox(Gecko),Internet Explorer,Opera和Safari支持的Node.contains
方法。 这里是一个例子:
var el = document.createElement("div"); console.log(document.body.contains(el)); // false document.body.appendChild(el); console.log(document.body.contains(el)); // true document.body.removeChild(el); console.log(document.body.contains(el)); // false
理想情况下,我们将使用document.contains(el)
,但在IE中不起作用,所以我们使用document.body.contains(el)
。
不幸的是,你仍然需要轮询,但是检查一个元素是否在文档中是非常简单的:
setTimeout(function test() { if (document.body.contains(node)) { func(); } else { setTimeout(test, 50); } }, 50);
如果您可以在页面中添加CSS,那么下面是另一个使用animation来检测节点插入的巧妙技巧: http : //www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/
你能不能做一个document.getElementById('newElementId');
看看是否回报真实。 如果没有,像你说的,等待100ms,然后再试一次?
而不是走DOM文档元素,只需使用element.ownerDocument
。 请参阅https://developer.mozilla.org/en-US/docs/DOM/Node.ownerDocument并执行此操作:;
element.ownerDocument.body.contains(element)
你很好。
您可以查询document.getElementsByTagName(“*”)。length或创build一个自定义的appendChild函数,如下所示:
var append = function(parent, child, onAppend) { parent.appendChild(child); if (onAppend) onAppend(child); } //inserts a div into body and adds the class "created" upon insertion append(document.body, document.createElement("div"), function(el) { el.className = "created"; });
更新
根据要求,将我的意见中的信息添加到我的文章中
John Resig对Ajaxian上的Peppy库有了一个评论 ,似乎表明他的Sizzle库可能能够处理DOM插入事件。 我很好奇,看看是否会有代码来处理IE
在轮询的概念之后,我读了一些元素属性,直到元素被附加到文档(例如element.scrollTop)才可用,也许你可以轮询,而不是做所有的DOM遍历。
最后一件事情:在IE中,可能值得探索的一种方法是使用onpropertychange事件。 我认为追加到文件是必然触发该事件至less有一个属性。
在一个完美的世界里,你可以勾住突变事件。 我怀疑他们即使在标准浏览器上也能可靠地工作。 这听起来像你已经实现了一个突变事件,所以你可能会添加这个使用本机突变事件,而不是支持这些浏览器的超时轮询。
我已经看到了通过比较document.body.innerHTML
到上次保存的.innerHTML
来监视更改的DOM更改实现,它不完全是优雅的(但工作)。 既然你最终要检查是否已经添加了一个特定的节点,那么你最好检查每个中断。
我能想到的改进是 使用 (看评论)。 或者使用.offsetParent
而不是.parentNode
因为它可能会削减您的循环中的一些父母 compareDocumentIndex()
IE外的所有compareDocumentIndex()
,并且testing.sourceIndex
对IE执行(如果节点不在DOM中,则应为-1)。
这也可能有助于: John Resig的X浏览器compareDocumentIndex实现 。
你想要DOMNodeInserted
事件(或DOMNodeInsertedIntoDocument
)。
编辑:这些事件完全可能不被IE支持,但我现在无法testing。
这是从jQuery代码中提取问题的另一个解决scheme。 下面的函数可以用来检查一个节点是否连接到DOM或者是否“断开”。
函数isDisconnected(节点){ 返回!节点|| !node.parentNode || node.parentNode.nodeType === 11; }
nodeType === 11定义了DOCUMENT_FRAGMENT_NODE,这是一个没有连接到文档对象的节点。
有关更多信息,请参阅John Resig的以下文章: http : //ejohn.org/blog/dom-documentfragments/
var finalElement=null;
我在循环中构builddom对象,当循环处于最后一个循环时,创buildlastDomObject
:
finalElement=lastDomObject;
离开循环:
while (!finalElement) { } //this is the delay...
下一个动作可以使用任何新创build的dom对象。 它在第一次尝试。
IE中不支持DOMNodeInserted或DOMNodeInsertedIntoDocument事件。 另一个从DOM的IE [only]特性中缺less的是compareDocumentPosition函数,它被devise用来做它的名字。
至于build议的解决scheme,我认为没有更好的(除非你做一些肮脏的窍门,如覆盖原生DOM成员的实现)
此外,更正问题的标题:dynamic创build的元素是DOM创build之时的一部分,可以附加到文档片段或其他元素,但可能不会附加到文档中。
我也认为你所描述的问题不是你有的问题,这个问题看起来是你潜在的解决scheme之一。 你能详细解释一下用例吗?