代码之家  ›  专栏  ›  技术社区  ›  Jason Bunting

如何确定动态创建的DOM元素是否已添加到DOM中?

  •  38
  • Jason Bunting  · 技术社区  · 16 年前

    According to spec ,只有 BODY FRAMESET 元素提供了一个要附加的“onload”事件,但我想知道动态创建的DOM元素是何时在JavaScript中添加到DOM的。

    我目前正在使用的超级天真的启发法有效,如下所示:

    • 横穿 返回节点

    • 如果最终祖先具有已定义的非空 身体

      • 假设所讨论的元素是dom的一部分
    • 其他的

      • 在100毫秒内再次重复这些步骤


    编辑:我想要一种不依赖浏览器的方式来实现这一点,不幸的是,我并不生活在一个只有一个浏览器的世界里;也就是说,我们非常感谢您提供特定于浏览器的信息,但请注意您知道的浏览器 在…工作。谢谢

    11 回复  |  直到 16 年前
        1
  •  30
  •   Community CDub    7 年前

    更新:对于任何对此感兴趣的人,以下是我最终使用的实现:

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

    我想要它的原因是提供一种合成 onload 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
    

    Darryl's answer 是因为getElementById技术仅在您位于同一文档中时有效;我在一个页面上有一些iFrame,页面之间以一些复杂的方式进行通信——当我尝试这个方法时,问题是它找不到元素,因为它是一个不同于它正在执行的代码的文档的一部分。

        2
  •  21
  •   Chris Calo SheetJS    12 年前

    Node.contains 方法,由Chrome、Firefox(Gecko)、Internet Explorer、Opera和Safari支持。以下是一个例子:

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

    http://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/

        3
  •  8
  •   Darryl Hein IrishChieftain    16 年前

    你不能做一件事吗 document.getElementById('newElementId');

        4
  •  8
  •   ydaniv    11 年前

    使用 element.ownerDocument . 请看这里: https://developer.mozilla.org/en-US/docs/DOM/Node.ownerDocument 这样做:

    element.ownerDocument.body.contains(element)
    

        5
  •  2
  •   Leo    16 年前

    document.getElementsByTagName(“*”).length 或创建自定义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";
    });
    

    使现代化

    通过请求,将我评论中的信息添加到我的帖子中

    有一个 comment by John Resig 关于Ajaxian上的Peppy库,这似乎表明他的Sizzle库可能能够处理DOM插入事件。我很好奇是否会有代码来处理IE

    根据轮询的思想,我读到一些元素属性在元素被附加到文档之前是不可用的(例如element.scrollTop),也许您可以轮询它而不是执行所有DOM遍历。

    最后一件事:在IE中,一种值得探索的方法是使用onpropertychange事件。我认为将其附加到文档中必然会触发至少一个属性的事件。

        6
  •  2
  •   Borgar    16 年前

    在一个完美的世界里,你可以钩住突变事件。我怀疑即使在标准浏览器上,它们也能可靠地工作。听起来您已经实现了一个变异事件,所以您可以添加它来使用本机变异事件,而不是在支持这些事件的浏览器上进行超时轮询。

    我见过DOM变更实现,它通过比较 document.body.innerHTML .innerHTML

    我能想到的改进是 使用 .offsetParent 而不是 .parentNode compareDocumentIndex() .sourceIndex

    这也可能有助于: X browser compareDocumentIndex implementaion by John Resig .

        7
  •  1
  •   eyelidlessness    16 年前

    你想要 DOMNodeInserted 事件(或 DOMNodeInsertedIntoDocument ).

        8
  •  1
  •   Elliot B.    7 年前

    A. MutationObserver 当元素被添加到DOM中时,应该使用它来检测。 现在,所有现代浏览器(Chrome 26+、Firefox 14+、IE11、Edge、Opera 15+等)都广泛支持MutationObserver。

    下面是一个简单的示例,说明如何使用 MutationObserver 侦听何时将元素添加到DOM。

    为简洁起见,我使用jQuery语法构建节点并将其插入DOM。

    var myElement = $("<div>hello world</div>")[0];
    
    var observer = new MutationObserver(function(mutations) {
       if (document.contains(myElement)) {
            console.log("It's in the DOM!");
            observer.disconnect();
        }
    });
    
    observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});
    
    $("body").append(myElement); // console.log: It's in the DOM!
    

    这个 observer 无论何时从中添加或删除任何节点,都将触发事件处理程序 document . 在处理程序内部,我们然后执行 contains myElement 现在在 .

    您不需要迭代存储在中的每个MutationRecord mutations document.contains 直接查看 myElement .

    文件 myElement 在DOM中。

        9
  •  0
  •   nik    15 年前

    以下函数可用于检查节点是否已连接到DOM或是否已“断开连接”。

    function isDisconnected( node ) {
        return !node || !node.parentNode || node.parentNode.nodeType === 11;
    }
    

    有关更多信息,请参阅John Resig的以下文章: http://ejohn.org/blog/dom-documentfragments/

        10
  •  0
  •   slm Vikas Hardia    12 年前
    var finalElement=null; 
    

    我在循环中构建dom对象,当循环在最后一个循环中并且 lastDomObject

     finalElement=lastDomObject; 
    

    离开循环:

    while (!finalElement) { } //this is the delay... 
    

    下一个操作可以使用任何新创建的dom对象。第一次尝试就成功了。

        11
  •  -1
  •   Sergey Ilinsky    16 年前

    域名插入 DOMNodeInsertedIntoDocument IE中支持事件。DOM的IE[仅]功能中缺少的另一个功能是 比较文件位置

    另外,请更正问题的标题:动态创建的元素从创建时起就是DOM的一部分,可以将其附加到文档片段或其他元素,但也可以不附加到文档。

    我还认为,你所描述的问题并不是你所面临的问题,这一问题似乎是解决你问题的潜在方法之一。你能详细解释一下这个用例吗?