“MutationObserver”上的“观察”:参数 1 不是“Node”类型

问题描述 投票:0回答:5

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

我正在使用 MutationObserver 来了解撰写框窗口何时出现。我通过观察具有类

no
的元素来执行此操作,因为撰写框元素是作为该元素的子元素创建的(类
no
)。

当用户单击撰写按钮并出现撰写框窗口时,我使用

.after()
方法在 SEND 按钮旁边放置一个元素。 SEND 按钮类名称为
.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" 
    ]
}

附注我已经尝试过 insertquery 库,但它有一些缺点。它不允许我具体说明特定元素的更改。我还没有尝试mutationsummary库,但由于它使用MutationObserver,我认为问题将持续存在。

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

但是,当我为所选元素添加

console.log
时,它显示为未定义。这意味着,您关于在节点存在之前执行代码的说法可能是正确的。你能告诉我如何确保延迟发生吗? “setTimeout”会起作用吗? MutationObserver 的情况下它是如何工作的?

javascript google-chrome-extension gmail gmail-api mutation-observers
5个回答
55
投票

正如我在评论中提到的,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 更改的活动量。

17
投票

尝试将其与 jQuery 一起使用。

如果您正在开发 Chrome 扩展程序,并且从 content_script 中的页面或 DOM 获取 HTML 元素(节点),那么您将获得对象,并且节点将作为对象的属性返回。然后,您可以从对象中获取 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.

6
投票

此错误意味着

document.querySelectorAll(".no")[2]
不是
Node

这很可能意味着不存在这样的元素;

querySelectorAll
将始终返回
NodeList
,即使它是空的;访问列表中不存在的成员会成功,不会出现运行时错误,但会返回
undefined
:从这个意义上说,
NodeList
的作用就像一个数组。

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

所以,需要等待这个根元素被添加;可能需要另一个

MutationObserver
来完成这项工作。


1
投票

如果您使用 jQuery,请将此代码放入

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

0
投票

就我而言,它是通过从

document.body
切换到
document.documentElement
来修复的:

  observer.observe(document.documentElement, {
      childList: true,
      subtree: true
  });
© www.soinside.com 2019 - 2024. All rights reserved.