是否有 JavaScript / jQuery DOM 更改侦听器?

Is there a JavaScript / jQuery DOM change listener?

提问人:Fletcher Moore 提问时间:5/17/2010 最后编辑:MikeFletcher Moore 更新时间:1/19/2022 访问量:357217

问:

从本质上讲,我希望在更改内容时执行脚本。由于脚本是分开的(Chrome扩展和网页脚本中的内容脚本),我需要一种方法来简单地观察DOM状态的变化。我可以设置轮询,但这似乎很草率。DIV

javascript jquery google-chrome-extension

评论

1赞 Lucio 7/18/2020
这回答了你的问题吗?检测 DOM 中的更改

答:

224赞 Anurag 5/17/2010 #1

编辑

此答案现已弃用。请看apsillers的答案。

由于这是针对 Chrome 扩展程序的,因此您不妨使用标准的 DOM 事件 - 。请参阅跨浏览器对此事件的支持。自 1.0 以来,Chrome 一直支持它。DOMSubtreeModified

$("#someDiv").bind("DOMSubtreeModified", function() {
    alert("tree changed");
});

请在此处查看工作示例。

评论

0赞 Peder Rice 7/26/2011
我注意到即使在某些选择器之后也可以触发此事件。我目前正在调查。
9赞 Maslow 1/5/2012
w3.org/TR/DOM-Level-3-Events/#event-type-DOMSubtreeModified 说这个事件已被弃用,我们会用什么来代替?
2赞 Sam Rueby 3/21/2012
@Maslow-没有!stackoverflow.com/questions/6659662/......
4赞 Capi Etheriel 10/2/2012
有 github.com/joelpurra/jquery-mutation-summary 基本上可以为jquery用户解决它。
1赞 concept47 12/20/2012
如果您正在构建 chrome 扩展程序,它仍然有效。无价的。
29赞 Zac Imboden 5/25/2012 #2

另一种方法取决于您如何更改 div。 如果使用 JQuery 通过其 html() 方法更改 div 的内容,则可以扩展该方法并在每次将 html 放入 div 时调用注册函数。

(function( $, oldHtmlMethod ){
    // Override the core html method in the jQuery object.
    $.fn.html = function(){
        // Execute the original HTML method using the
        // augmented arguments collection.

        var results = oldHtmlMethod.apply( this, arguments );
        com.invisibility.elements.findAndRegisterElements(this);
        return results;

    };
})( jQuery, jQuery.fn.html );

我们只是拦截对html()的调用,用这个调用一个注册函数,在上下文中指的是目标元素获取新内容,然后我们将调用传递给原始jquery.html(函数。请记住返回原始 html() 方法的结果,因为 JQuery 期望它用于方法链接。

有关方法覆盖和扩展的更多信息,请查看 http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm,这是我使用闭包函数的地方。另请查看 JQuery 网站上的插件教程。

558赞 apsillers 7/19/2012 #3

在很长一段时间里,DOM3 突变事件是最好的解决方案,但由于性能原因,它们已被弃用。DOM4 突变观察器是已弃用的 DOM3 突变事件的替代品。它们目前在现代浏览器中实现为(或在旧版本的 Chrome 中以供应商为前缀):MutationObserverWebKitMutationObserver

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations, observer) {
    // fired when a mutation occurs
    console.log(mutations, observer);
    // ...
});

// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
  subtree: true,
  attributes: true
  //...
});

此示例侦听 DOM 及其整个子树的更改,并将在元素属性更改以及结构更改时触发。规范草案包含有效突变侦听器属性的完整列表:document

儿童名单

  • 设置为如果要观察到目标子项的突变。true

属性

  • 设置为如果要观察到目标属性的突变。true

字符数据

  • 设置为如果要观察到目标数据的突变。true

子树

  • 设置为 if 突变不仅针对目标,还针对目标的后代。true

属性OldValue

  • 设置为 if 时,设置为 true 和 target 的属性值,然后才需要记录突变。trueattributes

字符数据旧值

  • 设置为 if 设置为 true,并且需要记录突变之前的目标数据。truecharacterData

attributeFilter(属性过滤器)

  • 如果不是所有属性突变都需要观察,则设置为属性本地名称列表(不带命名空间)。

(此列表是截至 2014 年 4 月的最新列表;您可以查看规范是否有任何更改。

评论

3赞 apsillers 3/25/2013
@AshrafBashir我看到示例在 Firefox 19.0.2 中工作正常:我看到登录到控制台,当我单击它时显示预期。请再次检查,因为这可能是 JSFiddle 中的临时技术故障。我还没有在 IE 中测试过它,因为我没有 IE 10,这是目前唯一支持突变事件的版本。([{}])MutationRecord
1赞 naugtur 3/7/2014
我刚刚发布了一个适用于 IE10+ 的答案,以及大多数其他任何内容。
1赞 Mr. Lance E Sloan 4/8/2014
该规范似乎不再有一个列出突变观察器选项的绿色框。它确实列出了第 5.3.1 节中的选项,并在其下方稍进一步描述了它们。
2赞 apsillers 4/8/2014
@LS谢谢,我已经更新了链接,删除了关于绿色框的部分,并将整个列表编辑到我的答案中(以防将来链接腐烂)。
4赞 bdesham 7/8/2014
下面是 Can I Use 中的浏览器兼容性表
9赞 Xan 5/10/2016 #4

除了 MutationObserver API 提供的“原始”工具之外,还有用于处理 DOM 突变的“方便”库。

考虑一下:MutationObserver 以子树的形式表示每个 DOM 更改。因此,例如,如果您正在等待插入某个元素,它可能位于 的子元素深处。mutations.mutation[i].addedNodes[j]

另一个问题是,当你自己的代码对突变做出反应时,会改变 DOM - 你经常想把它过滤掉。

一个很好的方便库是 mutation-summary(免责声明:我不是作者,只是一个满意的用户),它使您能够指定您感兴趣的内容的查询,并准确地获得它。

文档中的基本用法示例:

var observer = new MutationSummary({
  callback: updateWidgets,
  queries: [{
    element: '[data-widget]'
  }]
});

function updateWidgets(summaries) {
  var widgetSummary = summaries[0];
  widgetSummary.added.forEach(buildNewWidget);
  widgetSummary.removed.forEach(cleanupExistingWidget);
}
90赞 wOxxOm 9/15/2016 #5

许多网站使用 AJAX/XHR/fetch 来动态添加、显示、修改内容,并使用 window.history API 而不是网站内导航,以便以编程方式更改当前 URL。此类网站称为 SPA,是单页应用程序的缩写。


检测页面更改的常用 JS 方法

  • MutationObserverdocs) 从字面上检测 DOM 更改。

    信息/示例:

  • 通过发送 DOM 事件来发出内容更改信号的网站的事件侦听器

  • 通过 setInterval 定期检查 DOM
    显然,这仅在您等待其 id/选择器标识的特定元素出现时才有效,并且它不会让您普遍检测新的动态添加的内容,除非您发明了某种指纹识别现有内容。

  • 伪装历史 API

    let _pushState = History.prototype.pushState;
    History.prototype.pushState = function (state, title, url) {
      _pushState.call(this, state, title, url);
      console.log('URL changed', url)
    };
    
  • 监听 hashchangepopstate 事件:

    window.addEventListener('hashchange', e => {
      console.log('URL hash changed', e);
      doSomething();
    });
    window.addEventListener('popstate', e => {
      console.log('State changed', e);
      doSomething();
    });
    

P.S. 所有这些方法都可以在 WebExtension 的内容脚本中使用。这是因为我们正在查看的情况是通过 history.pushState 或 replaceState 更改 URL,因此页面本身在相同的内容脚本环境中保持不变。