替代 DOMNodeInserted

IT技术 javascript dom firefox-addon dhtml mutation-events
2021-03-01 12:51:39

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

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

5个回答

如果您正在创建针对最近的手机和更新版本的浏览器(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);
@naugtur 轮廓是个好主意,尤其是如果您可以仅对颜色进行虚拟动画。我可能会用它更新这个线程和我的博客文章。
2021-04-30 12:51:39
@naugtur 现在已经在 Github 上更新了,我已经调整了这个答案以匹配 - 感谢您的提醒!
2021-05-07 12:51:39
很抱歉这么说,但现在你只是让人们感到困惑。您帖子中的代码远非跨浏览器(动画事件有前缀,动画本身需要其他前缀)而且我从未说过您可以仅对颜色进行动画处理。这不是我测试的。
2021-05-10 12:51:39
这是迄今为止DOMNodeInserted我见过的最优秀的替代品事实上,我已经使用它几个月了,而且效果很好。
2021-05-11 12:51:39
该技术可以应用于 IE10+,但clip: rect不适用于 IE10(不确定 11)。outline在我的insertionQuerygithub.com/naugtur/insertionQuery 中使用
2021-05-15 12:51:39

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

但是,Mutation Observers 不提供基于 CSS 选择器的突变的通知,这是一个非常有用的功能。我有一个小module,它包装了上面的关键帧解决方案,使 CSS 选择器监听更容易:github.com/csuwildcat/SelectorListener
2021-04-24 12:51:39
认为@csuwldcat 的建议已经过时了——Mutation Observers 可以检测到您可能从 CSS 选择器(使用)以及更多(节点删除、文本节点更改)推断出的任何更改attributes
2021-05-08 12:51:39
@Barney 我已经用另一个用例更新了我的答案,它清楚地说明了这种方法可以轻松完成哪些 Mutation Observers 无法做到的事情。
2021-05-10 12:51:39
@Barney 有几件事:1)您可以使用此方法侦听选择器匹配,这对于 Mutation Observers 是不可能的-有关其提供的更多信息,请参见:github.com/csuwildcat/SelectorListener,以及 2)Mutation Observers 不是IE9、Safari 5、6 等旧浏览器支持。
2021-05-15 12:51:39

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

这是张贴在这里,因为这个问题是我在 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
});

如果您只想在 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);
哈哈哈,我刚登录就给你们鼓掌了……这些评论,果然是金子。
2021-04-22 12:51:39
转到像 msnbc.com 这样的大网站,并注意该getElementsByTagName("*")收藏有多少我得到了“2605”元素。你不能认真地认为这是个好主意。
2021-04-27 12:51:39
不是真的,但很棒的评论。如果需要,您可以将最后一个小“1”更改为 500。这将每半秒更新一次,而不是(最多)每秒 1000 次。
2021-05-07 12:51:39
这是一段糟糕的代码,会毁掉它插入的任何页面。
2021-05-08 12:51:39
是的*,仅 CSS 中运算符就很昂贵。也请不要加alert(...)和 1 毫秒的民意调查 omg!
2021-05-16 12:51:39