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

IT技术 javascript google-chrome-extension gmail gmail-api mutation-observers
2021-02-26 02:24:30

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

我正在使用 MutationObserver 来了解撰写框窗口何时出现。我通过观察带有 class 的元素来做到这一点,no因为 compose box 元素是作为该元素 (class 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" 
    ]
}

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

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

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

4个回答

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

尝试在 jQuery 中使用它。

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

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

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

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

所以,你需要等待这个根元素被添加;可能,与另一个人MutationObserver一起做这项工作。

感谢@Xan 帮助我,你对这个问题是正确的,我现在已经使用 Makyen 在另一个答案中建议的“setTimeout”解决了这个问题。仅供参考:我没有使用另一个mutationobserver,因为它是资源密集型的,尽管比mutationevents 好,但我认为肯定比setTimeout 多。再次感谢。
2021-05-04 02:24:30

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

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