检测/监控 DOM 变化的最有效方法?

Posted

技术标签:

【中文标题】检测/监控 DOM 变化的最有效方法?【英文标题】:Most efficient method of detecting/monitoring DOM changes? 【发布时间】:2011-01-28 06:15:27 【问题描述】:

我需要一种有效的机制来检测对 DOM 的更改。最好是跨浏览器,但如果有任何跨浏览器的有效方法,我可以使用故障安全的跨浏览器方法来实现这些。

特别是,我需要检测会影响页面文本的更改,因此需要任何新的、已删除或修改的元素,或对内部文本 (innerhtml) 的更改。

我无法控制所做的更改(它们可能是由于包含 3rd 方 javascript 等),因此无法从这个角度进行处理 - 我需要以某种方式“监控”更改。

目前我已经实现了一个“quick'n'dirty”方法,它会每隔一段时间检查body.innerHTML.length。这当然不会检测到导致返回相同长度的更改,但在这种情况下“足够好” - 发生这种情况的可能性非常小,在这个项目中,无法检测到更改不会导致在丢失的数据中。

body.innerHTML.length 的问题在于它很贵。在 fast 浏览器上可能需要 1 到 5 毫秒,这会使事情陷入困境——我还要处理大量的 iframe,这一切都加起来了。我很确定这样做的代价是因为 innerHTML 文本不是由浏览器静态存储的,每次读取时都需要从 DOM 中计算出来。

我正在寻找的答案类型是从“精确”(例如事件)到“足够好”的任何类型 - 可能像 innerHTML.length 方法一样“快速'n'dirty”,但执行更快。

编辑: 我还应该指出,虽然检测已修改的精确元素会“很好”,但这并不是绝对必要的——只要有 any 更改这一事实就足够了.希望这能扩大人们的反应。我将研究 Mutation Events,但我仍然需要 IE 支持的后备,因此非常欢迎任何古怪的、有创意的、不合常规的想法。

【问题讨论】:

上次被问到这个问题时运气不佳:***.com/questions/648996/… 是的,我看到了,你说得对……运气不好。 然而,因为我不需要 100% 的准确率,也因为我不需要确定哪个元素发生了变化,只要 发生了变化,我我希望人们为我想出一些创造性的解决方案...... Is there a JavaScript/jQuery DOM change listener?的可能重复 【参考方案1】:

我最近写了一个插件来做到这一点 - jquery.initialize

你的使用方式和.each函数一样

$(".some-element").initialize( function()
    $(this).css("color", "blue"); 
);

.each 的不同之处在于 - 它采用您的选择器,在本例中为.some-element,并等待将来使用此选择器的新元素,如果要添加这样的元素,它也会被初始化。

在我们的例子中,初始化函数只是将元素颜色更改为蓝色。因此,如果我们要添加新元素(无论是使用 ajax 还是 F12 检查器或其他任何东西),例如:

$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!

插件会立即启动它。插件还确保一个元素只初始化一次。所以如果你添加元素,然后从body中.deatch()它,然后再次添加它,它不会再次初始化。

$("<div/>").addClass('some-element').appendTo("body").detach()
    .appendTo(".some-container");
//initialized only once

插件基于MutationObserver - 它可以在 IE9 和 10 上运行,其依赖关系详见 readme page。

【讨论】:

【参考方案2】:

为了更新这一点,DOM4 标准取消了 Mutation Events 并用 Mutation Observers 替换它们:https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

【讨论】:

【参考方案3】:

jQuery Mutate 也可以这样做,默认情况下它支持height, width, scrollHeight 等...但它也可以通过一些额外的代码来扩展以添加新事件,例如查看文本已经改变等等......

http://www.jqui.net/jquery-projects/jquery-mutate-official/

希望对你有帮助

【讨论】:

【参考方案4】:

http://www.quirksmode.org/js/events/DOMtree.html

jQuery 现在支持将事件附加到与选择器相对应的现有和未来元素:http://docs.jquery.com/Events/live#typefn

另一个有趣的发现 - http://james.padolsey.com/javascript/monitoring-dom-properties/

【讨论】:

谢谢,这似乎涵盖了所有基础 - 非 IE 的 DOMTree 事件和 IE 的 onPropertyChange。我还没有实现 onPropertyChange 事件,但会实现 - 请参阅 @Gaby 帖子上的我的 cmets,了解到目前为止所做的更新。 jQuery 的 live() 方法似乎在 IE 中效果不佳,所以我也使用标准的 bind()(然后 unbind().bind() 用于任何更改,以防添加任何新内容),但使用 DOMTree 事件以及onPropertyChange 和 setInterval 后备,似乎可以解决问题。 watch() 似乎太麻烦了(必须手动添加到所有元素,因为它不是标准事件类型,它只是一种方法),我不确定它是否在各种浏览器中得到正确支持,而其他两种方法似乎覆盖了大多数基地。 仅供参考:“从 jQuery 1.7 开始,不推荐使用 .live() 方法。使用 .on() 附加事件处理程序。旧版本 jQuery 的用户应优先使用 .delegate() 。居住()。” from docs 补充仅供参考:mozilla docs 说观察突变事件已被弃用,应替换为“突变观察者”。不过,我不知道突变观察者是否完全可用。【参考方案5】:

您可以尝试使用 DOMNodeInserted 和 DOMNodeRemoved 事件。根据 Quirksmode,它们在大多数浏览器中都可以工作,除了 IE...

http://www.quirksmode.org/dom/events/index.html

【讨论】:

它们是在 DOM 级别 2 中引入的两种 Mutation Event 类型。存在更多的事件类型..【参考方案6】:

Mutation events 是您正在寻找的 W3 推荐..

不确定它们是否全面支持..(IE 很可能不支持它们..)

【讨论】:

我现在正在使用这些事件 - 我仍在按设定的时间间隔检查 body.innerHTML.length,但如果触发了这些事件中的任何一个,我假设不再需要定期检查并将其关闭。我仍在调查onPropertyChangewatch() 作为替代方案,并且可能会使用类似的想法来实现这些,因为如果它们被触发,我可以取消任何其他检查-onPropertyChange 可能在 IE 中工作,但在其他浏览器。 突变事件目前已被弃用,有利于突变观察者developer.mozilla.org/en-US/docs/Web/API/MutationObserver

以上是关于检测/监控 DOM 变化的最有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

Java使用长纪元时间戳来检测日变化的最有效方法

html5监控某个dom变化

4种方法实时监控Linux日志文件

监控 Applescript 中的 Spotify 曲目变化?

iOS监控/监测/监听文件/文件夹的变化 检测文件变化

C#Aforge检测画面变化自动拍照