【问题标题】:Is there a JavaScript / jQuery DOM change listener?是否有 JavaScript / jQuery DOM 更改侦听器?
【发布时间】:2021-01-14 04:04:02
【问题描述】:

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

【问题讨论】:

标签: javascript jquery google-chrome-extension


【解决方案1】:

许多站点使用 AJAX/XHR/fetch 来动态添加、显示、修改内容,并使用 window.history API 代替站点内导航,因此当前 URL 以编程方式更改。此类网站称为 SPA,是 Single Page Application 的缩写。


检测页面变化的常用JS方法

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

【讨论】:

    【解决方案2】:

    长期以来,DOM3 突变事件是可用的最佳解决方案,但由于性能原因,它们已被弃用。 DOM4 Mutation Observers 是已弃用的 DOM3 突变事件的替代品。它们是 currently implemented in modern browsersMutationObserver (或者在旧版 Chrome 中以供应商为前缀的 WebKitMutationObserver):

    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
      //...
    });
    

    此示例侦听document 及其整个子树上的 DOM 更改,并将触发元素属性的更改以及结构更改。规范草案有一个完整的有效mutation listener properties列表:

    子列表

    • 如果要观察目标子代的突变,则设置为 true

    属性

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

    字符数据

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

    子树

    • 如果不仅要观察目标突变,还要观察目标后代的突变,则设置为 true

    attributeOldValue

    • 如果 attributes 设置为 true 并且目标的属性值需要记录突变之前,则设置为 true

    characterDataOldValue

    • 如果characterData 设置为true,则设置为true,并且需要记录突变前的目标数据。

    属性过滤器

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

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

    【讨论】:

    • @AshrafBashir 我看到示例在 Firefox 19.0.2 中运行良好:我看到 ([{}]) 登录到控制台,当我单击它时显示预期的 MutationRecord。请再次检查,因为它可能是 JSFiddle 中的临时技术故障。我还没有在 IE 中测试过,因为我没有 IE 10,这是目前唯一支持突变事件的版本。
    • 我刚刚发布了一个适用于 IE10+ 和其他任何东西的答案。
    • 规范似乎不再有一个绿色框来列出变异观察者选项。它在第 5.3.1 节中使用了list the options,并在下面稍稍描述了它们。
    • @LS 谢谢,我已经更新了链接,删除了关于绿色框的部分,并将整个列表编辑到我的答案中(以防将来链接失效)。
    【解决方案3】:

    编辑

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

    由于这是针对 Chrome 扩展程序,您不妨使用标准 DOM 事件 - DOMSubtreeModified。请参阅跨浏览器对此event 的支持。 Chrome 从 1.0 开始就支持它。

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

    查看工作示例here

    【讨论】:

    【解决方案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);
    }
    

    【讨论】:

      【解决方案5】:

      另一种方法取决于您如何更改 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() 的调用,用 this 调用一个注册函数,在上下文中是指目标元素获取新内容,然后我们将调用传递给原始 jquery.html() 函数。请记住返回原始 html() 方法的结果,因为 JQuery 期望它用于方法链接。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多