观察目标节点上尚不存在的突变

Posted

技术标签:

【中文标题】观察目标节点上尚不存在的突变【英文标题】:Observe mutations on a target node that doesn't exist yet 【发布时间】:2016-12-17 07:17:23 【问题描述】:

是否可以在尚不存在的 DOM 节点上观察突变?

示例:

我的应用有时会创建一个 div:<div id="message" data-message-content="foo" data-message-type="bar" />

我想关注这个 div 的创建和变化。

var mutationObserver = new MutationObserver(function(mutations)
  // Some code to handle the mutation.
);

mutationObserver.observe(
    document.querySelector('#message'),
         
            attributes: true, 
            subtree: true, 
            childList: true, 
            characterData: false 
        
    );
);

现在这会返回一个错误,因为#message 为空(尚未创建 div)。

Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.

一个明显的解决方案是观察body 并检查是否有任何突变是div#Message 的创建,但这似乎是个坏主意/或者可能对性能不利。

【问题讨论】:

你是如何创建元素的?您不能在创建它的相同方法中添加它以便实际创建它吗? 很遗憾,它是针对 Google Chrome 插件的。插件有一些恼人的范围限制。基本上,这个观察者存在于与创建 div 的窗口/函数完全不同的范围内。 显而易见的解决方案是唯一的解决方案,除非站点在添加该节点之前发出某种事件。 Refer this answer how I fixed it ***.com/questions/61212681/… 【参考方案1】:

只能观察现有节点。

但不要担心,因为 getElementById 与枚举所有突变的添加节点相比非常快,所以等待元素出现根本不会像您在 Devtools -> Profiler 面板中看到的那样费力。

function waitForAddedNode(params) 
    new MutationObserver(function(mutations) 
        var el = document.getElementById(params.id);
        if (el) 
            this.disconnect();
            params.done(el);
        
    ).observe(params.parent || document, 
        subtree: !!params.recursive || !params.parent,
        childList: true,
    );

用法:

waitForAddedNode(
    id: 'message',
    parent: document.querySelector('.container'),
    recursive: false,
    done: function(el) 
        console.log(el);
    
);

始终使用 devtools 分析器并尝试使您的观察者回调消耗的 CPU 时间少于 1%。

尽可能观察未来节点的直接父节点 (subtree: false) 在 MutationObserver 回调中使用 getElementById、getElementsByTagName 和 getElementsByClassName,避免使用 querySelector,尤其是速度极慢的 querySelectorAll。 如果在 MutationObserver 回调中绝对无法避免 querySelectorAll,请先执行 querySelector 检查,平均而言这样的组合会快得多。 不要在 MutationObserver 回调中使用需要回调的数组方法,如 forEach、filter 等,因为在 javascript 中,函数调用与经典的 for (var i=0 ....) 循环相比是一项昂贵的操作,并且 MutationObserver 回调可能每秒触发 100 次在复杂的现代页面上,每批突变中有数十、数百或数千个addedNodes。 请勿在 MutationObserver 回调中使用 the slow ES2015 loops 之类的 for (v of something),除非您进行了转编译并且生成的代码运行速度与经典的 for 循环一样快。

【讨论】:

Welp,这是我在这里得到的最深入(关于性能)的答案之一。谢谢! 一种巧妙的方法,因为您不依赖于突变属性(我遇到了困难),而是每次都检查所需的元素是否存在。有点像超时轮询。虽然依赖于具有 id 的元素...

以上是关于观察目标节点上尚不存在的突变的主要内容,如果未能解决你的问题,请参考以下文章

Oracle Apex 页面进程不存在条件问题

CSS Font Face,仅在字体不存在时下载

突变中的 GraphQL 嵌套节点 - 对象文字只能指定已知属性,并且类型中不存在“天”

是否可以随机设置文档中尚不存在的名称?

如何使用添加查询添加表中尚不存在的记录

sql 添加列(如果它尚不存在)