Firefox Add-on SDK 上下文菜单与页面加载的内容脚本通信-mod

Firefox Add-on SDK context-menu communicate with a content script loaded by page-mod

我正在使用 Firefox 附加组件 SDK 创建一个 Firefox 附加组件。这个插件做了两件事:

  1. 使用 sdk/page-mod 在每个页面中注入内容脚本。
  2. 使用 sdk/context-menu 添加上下文菜单项。

我希望当用户单击上下文菜单项时,加载项将调用由 PageMod() 加载的内容脚本中的函数。

除非您的 page-mod 脚本正在做其他事情,否则听起来使用 context-menu contentScript or contentScriptFile 属性加载它可能更合适。或者,使用此方法加载上下文菜单所需的部分。如何最好地拆分您正在使用的脚本取决于您实际在做什么。没有您提供的更多信息,很难提供具体的建议。

在不同时间或通过不同方法加载的内容脚本之间进行通信:

没有直接为所欲为的方法。不同的上下文中加载的内容脚本不是通过相同的方法同时加载的。它们之间无法直接调用函数。同时加载的多个内容脚本和相同的方法共享相同的context/scope并且可以在它们之间直接调用函数。

但是,您可以communicate between content scripts。如果它们 加载到同一页面,那么您将需要通过使用主 add-on 脚本从一个内容脚本与另一个内容脚本进行通信,以首先从一个内容接收消息脚本。然后,您的主要 add-on 脚本将需要向第二个内容脚本发送第二条消息(可能包含完全相同的数据)。换句话说,您的主要 add-on 代码需要在两个内容脚本之间中继消息。

对于通过不同方法加载到同一页面的内容脚本(例如,一个使用 page-mod,另一个作为上下文菜单项——您感兴趣的情况),您可以在它们之间直接通信使用 DOM postMessage() API or a CustomEvent。 Either 可用于在两个脚本之间发送您想要的任何 JSON 可序列化数据。 DOM postMessage() API 提供了更多的安全性,但有点复杂。有了它,您还必须过滤掉通过随机代码发送给它的任何其他 "message" 事件。如果您要让已发布的代码 add-on 根据消息的内容执行函数,则可能应该使用它。这是一个安全问题,具体取决于您对消息的处理方式。

示例:

以下代码会将 page-mod 脚本加载到每个匹配 "*.mozilla.org" 的页面中。它还会在 link 上显示的那些相同页面中创建上下文菜单项。单击上下文菜单项将从 context-menu 内容脚本发送一个事件,其中包含显示上下文菜单的 URL 的数据。 page-mod 脚本将接收自定义事件。然后 page-mod 脚本将针对 link.

发出带有 URL 的警报
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScript: 'function contextMenuAlert(href) {'
               + '    window.alert("The context menu click on a link with URL:\n" + href);'
               + '};'
               + 'window.addEventListener("myAddonId-contextMenu-clicked",'
               + '    function(event){contextMenuAlert(event.detail);});'
});

//Context menu
let cm = require("sdk/context-menu");
cm.Item({
    label: "Alert link URL",
    context: [
        cm.URLContext(["*.mozilla.org"]),
        cm.SelectorContext("a[href]")
    ],
    contentScript: 'self.on("click", function (node, data) {'
                 + '    var event = new CustomEvent("myAddonId-contextMenu-clicked",'
                 + '                                {detail:node.href});'
                 + '    window.dispatchEvent(event);'
                 + '});'
});

以上代码生成如下所示的上下文菜单:

单击时,page-mod 添加的内容脚本会启动以下警报:

使用发送的消息从多个不同的功能中进行选择:

可以扩展通过事件传递的信息,以允许根据内容调用多个不同的函数。这样做的一种方法是发送一个对象作为消息。对象的一个​​ 属性 可以是所需的功能,另一个可以是在该功能中使用的数据。我对以下问题的回答包含了这样做的例子:

  • :此答案的代码使用相同的传递消息来指示在上下文菜单项上进行了单击并传递了单击上下文菜单项的 URL , 或者告诉主脚本上下文菜单即将显示以便可以修改。
  • :此答案显示发送一条消息,该消息将导致调用各种不同的函数之一并将数据传递给被调用的函数。它是作为一种使用 console 方法的方式从一个只有 console.log("message") 的工作人员那里实现的。如果我今天这样做,我的代码会有点不同,但它有效并展示了这个概念。

因为 MDN (here and here) 上的文档对内容脚本到内容脚本的通信不是很清楚,我已经更新了我找到的讨论它的页面。我还添加了上面的代码作为示例。