30

众所周知,DOMNodeInserted 会使动态页面变慢,MDN 甚至建议不要完全使用它,但没有提供任何替代方案。

我对插入的元素不感兴趣,我只需要知道某些脚本何时修改了 DOM。是否有更好的替代突变事件侦听器(可能是 nsiTimer 中的 getElementsByTagName)?

4

6 回答 6

44

如果您正在创建一个针对最近的手机和较新版本的浏览器(Firefox 5+、Chrome 4+、Safari 4+、iOS Safari 3+、Android 2.1+)的网络应用程序,您可以使用以下代码创建一个很棒的插入 dom 节点的事件,它甚至在最初是页面静态标记的一部分的节点上运行!

这是完整帖子的链接和示例:http ://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/

关于 Mutation Observers 的注意事项:虽然最近浏览器中较新的 Mutation Observers 功能非常适合监视对 DOM 的简单插入和更改,但请理解此方法可以用来做更多事情,因为它允许您监视任何与您匹配的 CSS 规则可以的。这对于许多用例来说都非常强大,所以我在这里将它封装在一个库中:https ://github.com/csuwildcat/SelectorListener

如果要针对各种浏览器,则需要在 CSS 和 animationstart 事件名称中添加适当的前缀。您可以在上面链接的帖子中阅读更多相关信息。

基本节点插入案例

CSS

@keyframes nodeInserted {  
    from {  
        outline-color: #fff; 
    }
    to {  
        outline-color: #000;
    }  
}

div.some-control {
    animation-duration: 0.01s;
    animation-name: nodeInserted;
}

JavaScript

document.addEventListener('animationstart', function(event){
    if (event.animationName == 'nodeInserted'){
        // Do something here
    }
}, true);

侦听更复杂的选择器匹配:

这使得使用 Mutation Observers 几乎不可能完成的事情成为可能

CSS

@keyframes adjacentFocusSequence {  
    from {  
        outline-color: #fff; 
    }
    to {  
        outline-color: #000;
    }  
}

.one + .two + .three:focus {
    animation-duration: 0.01s;
    animation-name: adjacentFocusSequence;
}

JavaScript

document.addEventListener('animationstart', function(event){
    if (event.animationName == 'adjacentFocusSequence'){
        // Do something here when '.one + .two + .three' are 
        // adjacent siblings AND node '.three' is focused
    }
}, true);
于 2012-04-27T02:12:06.330 回答
11

@naugtur 简要提到的一种新选择是MutationObserver。如果您正在开发的浏览器支持它(例如,如果您正在开发浏览器扩展),它被设计为替代已弃用的突变事件。

于 2013-06-29T00:53:21.390 回答
0

与所描述的 csuwldcat 相同的技术已被制作成一个易于使用的 jQuery 插件(如果这是你的事):https ://github.com/liamdanger/jQuery.DOMNodeAppear

于 2014-12-02T00:26:48.693 回答
0

尝试使用customElements,但不要用于已经创建的元素!

customElements.define( 'insertion-triggerable', class extends HTMLElement {
    connectedCallback() {
        console.log( 'connected' )
    }

    disconnectedCallback() {
        console.log( 'disconnected' )
    }

    adoptedCallback() {
        console.log( 'adopted' )
    }
} );

let element = document.createElement( 'insertion-triggerable' );

或者

customElements.define( 'insertion-triggerable', class extends HTMLDivElement {
    // --||--
}, { extends: 'div' } );

let divElement = document.createElement( 'div', { is: 'insertion-triggerable' } );
于 2022-02-02T21:51:29.613 回答
-1

之所以在此处发布此问题,是因为我在此问题上寻求 DOMNodeInserted 在 IE9 中失败的帮助,但请注意,此解决方案专门针对在使用 End Request 函数的 ASP.NET 上下文中使用 jQuery 的情况。您的里程可能会有所不同,等等......

基本上,我们将完全丢弃 DOMNodeInserted 并使用 End Request 来加载我们的事件处理程序:

老的:

$(document).ready(function() {

$(document).bind('DOMNodeInserted', function(event){
My jQuery event handler...

 }); 
});

====================================

新的:

function Ajax_EndRequest {
  function2();
}

function2 (a,b){
  My jQuery event handler...
}

$(document).ready(function(){
  add_endRequest(Ajax_EndRequest); //this is what actually invokes the function upon request end.

 My jQuery event handler...//REMOVED -- don't need this now
});
于 2013-01-14T22:45:03.633 回答
-22

如果您只想在 DOM 更改时触发一个事件,请执行以下操作:

var nodes=document.getElementsByTagName('*')||document.all;

function domchange(){
    alert('Hello');
}

window.setInterval(function(){
    var newnodes=document.getElementsByTagName('*')||document.all;
    if(newnodes!=nodes){
        nodes=newnodes;
        domchange();
    }
},1);
于 2011-08-16T05:39:06.877 回答