【问题标题】:'observe' on 'MutationObserver': parameter 1 is not of type 'Node'“MutationObserver”上的“观察”:参数 1 不是“节点”类型
【发布时间】:2017-03-16 20:01:23
【问题描述】:

我正在创建一个 Chrome 扩展程序并尝试在 gMail 撰写框的发送按钮旁边包含一个小文本。

我正在使用 MutationObserver 来了解撰写框窗口何时出现。我通过观察类no 的元素来做到这一点,因为撰写框元素是作为该元素的子元素(no 类)创建的。

当用户单击撰写按钮并出现撰写框窗口时,我使用.after() 方法在发送按钮旁边放置一个元素。发送按钮类名是.gU.Up

这些是 gMail 的真实类名,也很奇怪。

下面是我正在使用的代码:

var composeObserver = new MutationObserver(function(mutations){ 
    mutations.forEach(function(mutation){
        mutation.addedNodes.forEach(function(node){
            $(".gU.Up").after("<td> <div> Hi </div> </td>");
        });
    });
});

var composeBox = document.querySelectorAll(".no")[2];
var config = {childList: true};
composeObserver.observe(composeBox,config);

问题是我经常收到以下错误:

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

有人可以帮忙吗?我已经尝试了很多东西,也在这里查看了其他答案,但仍然无法摆脱这个错误。

这是我的 manifest.json 文件:

{
    "manifest_version": 2,
    "name": "Gmail Extension",
    "version": "1.0",

    "browser_action": {
        "default_icon": "icon19.png",   
        "default_title": "Sales Analytics Sellulose"    
    },

    "background": {
        "scripts": ["eventPage.js"],
        "persistent": false
    },

    "content_scripts": [
    {
        "matches": ["https://mail.google.com/*"],
        "js": ["jquery-3.1.1.js", "insQ.min.js", "gmail_cs.js"]
    }
],

    "web_accessible_resources":[
        "compose_icon.png",
        "sellulosebar_icon.png" 
    ]
}

附:我已经尝试过插入查询库,但它有一些缺点。它不允许我具体说明特定元素的变化。我还没有尝试过mutationsummary 库,但由于它使用了MutationObserver,我认为这个问题会持续存在。

从评论中添加:
确实,选择器没有给我一个节点。我检查了控制台,它给出了一个对象。我还检查了控制台,它正在选择我想要观察的适当元素。

但是,当我为所选元素添加 console.log 时,它显示为未定义。这意味着,您可能对在节点出现之前执行代码是正确的。你能告诉我如何确保延迟发生吗? 'setTimeout' 会起作用吗?在 MutationObserver 的情况下它是如何工作的?

【问题讨论】:

  • 该错误清楚地表明document.querySelectorAll(".no")[2] 的结果不会评估为Node。您将需要查看页面的结构以确定如何选择适当的节点。您的代码可能/很可能在您希望在 DOM 中找到存在的节点之前执行。如果是这样,您将需要延迟添加观察者,直到它们存在(许多方法可以这样做)。
  • 感谢@Makyen 我已经添加了清单文件。确实,选择器没有给我一个节点,我在控制台中签入,它给了一个对象。我还检查了控制台,它正在选择我想要观察的适当元素。

    但是,当我为选定的元素添加“console.log”时,它是未定义的。这意味着,您可能对在节点出现之前执行代码是正确的。你能告诉我如何确保延迟发生吗? 'setTimeout' 会起作用吗?在mutationobserver的情况下它是如何工作的?

标签: javascript google-chrome-extension gmail gmail-api mutation-observers


【解决方案1】:

正如我在评论中提到的,并且 Xan 给出了一个答案,该错误清楚地表明 document.querySelectorAll(".no")[2] 的结果不会评估为 Node

根据您在评论中提供的信息,很明显问题在于您希望观察的节点在您的代码执行时不存在。有很多方法可以延迟代码的执行,直到该节点可用。一些可能性是:

  1. 使用 setTimeout 循环进行轮询,直到检测到要放置 MutationObserver 的元素可用:

    function addObserverIfDesiredNodeAvailable() {
        var composeBox = document.querySelectorAll(".no")[2];
        if(!composeBox) {
            //The node we need does not exist yet.
            //Wait 500ms and try again
            window.setTimeout(addObserverIfDesiredNodeAvailable,500);
            return;
        }
        var config = {childList: true};
        composeObserver.observe(composeBox,config);
    }
    addObserverIfDesiredNodeAvailable();
    

    这将在它存在于 DOM 中之后很快找到合适的节点。此方法的可行性取决于插入目标节点后多久需要将观察者放置在其上。显然,您可以根据需要调整轮询尝试之间的延迟。

  2. 创建另一个 MutationObserver 以观察 DOM 中更高的祖先节点,以便插入您想要放置主要观察者的节点。虽然这会在插入时立即找到合适的节点,但它可能会占用大量资源 (CPU),具体取决于您必须观察的 DOM 的高度以及与 DOM 更改相关的活动量。

【讨论】:

  • 好吧..我尝试了第一种和第二种方式,但还没有第三种。第一个 - 我认为你的意思是 document_end 因为 document_idle 是“run_at”的默认状态,但无论如何。使用 'document_end' 不会执行整个内容脚本。第二 - 它工作但我现在有一个问题,因为我在 SEND 按钮旁边添加一个元素,我使用 '$(".SendButtonClass").after()' 。问题是,如果我再打开一个撰写框,那么对于第一个撰写框,'$(".SendButtonClass").after()' 也会执行两次。感谢您迄今为止的帮助。
  • 只是为了让你知道:我想出了另一个解决方案,在不使用观察者的情况下在发送按钮旁边添加元素。我正在观看撰写按钮以进行单击并添加回调以及 setTimeout 以进行所需的更改。
  • @geetmehar,我不应该包含 #1(现已删除)。当默认值实际上是document_idle 时,我忘记了默认值document_end。因此,这个建议毫无用处。很抱歉浪费您的时间。使用document_end 不应该阻止您的脚本运行,除非有其他一些依赖项在其他地方引发了错误。要诊断您报告的新问题,我需要查看更多代码,这确实应该是一个新问题(链接到此问题以获取上下文。(续)
  • @geetmehar,(续)问题的简短描述听起来像是添加了太多次事件侦听器(或者至少这是典型模式的开始)。 MutationObservers 之外的其他解决方案通常更好。什么是最合适的取决于您的代码、您正在尝试执行的操作以及您正在执行操作的页面。如果不查看所有代码,很难评论哪个更好。但是,除非必要,否则我通常倾向于不使用 MutationObserver,因为它们往往会占用大量 CPU。
  • @oldboy 不,不可能使用 MutationObserver 来观察 Object 的变化。
【解决方案2】:

尝试在 jQuery 中使用它。

如果您正在开发 Chrome 扩展程序并且您正在从页面或 content_script 中的 DOM 获取 HTML 元素(节点),那么您将获得 Object 并且 Node 将作为 Object 的属性返回。然后,您可以从 Object 中获取 Node 以传递给 observe(Node,config) 方法。

示例

var node = $("#elementId");  //this is wrong because if you logged this in the console you will get Object

var node = $("#elementId")[0];  //This gives the first property of the Object returned, and this is correct because if you logged this in the console you will get the Node element for which you want to detect changes in the DOM.

【讨论】:

    【解决方案3】:

    这个错误意味着document.querySelectorAll(".no")[2]不是Node

    这很可能意味着没有这样的元素; querySelectorAll 将始终返回 NodeList,即使它是空的;访问列表中不存在的成员会成功,不会出现运行时错误,但会返回 undefined:在这个意义上,NodeList 就像一个数组。

    “等等,但确实如此!我在控制台中运行这段代码,它就可以工作了!”你可能会惊呼。那是因为在您执行它时,在文档完成加载很久之后,这些元素仍然存在。

    所以,你需要等待这个根元素被添加;很可能,有另一个 MutationObserver 来完成这项工作。

    【讨论】:

    • 感谢@Xan 帮助我,您对这个问题是正确的,我现在使用 Makyen 在另一个答案中建议的“setTimeout”对其进行了整理。仅供参考:我没有使用另一个突变观察器,因为它是资源密集型的,尽管比突变事件更好,但我认为绝对超过 setTimeout。再次感谢。
    【解决方案4】:

    如果你使用jQuery,把这段代码放在

    $(document).ready(function(){ // your code });
    

    【讨论】:

    • 虽然这可能会有所帮助,但根据观察到的元素的加载/创建方式,它可能仍然不可用。 (问我怎么知道的。)
    猜你喜欢
    • 1970-01-01
    • 2021-05-06
    • 1970-01-01
    • 2018-12-21
    • 2021-02-08
    • 1970-01-01
    • 2015-01-20
    • 1970-01-01
    • 2013-07-25
    相关资源
    最近更新 更多