Mozilla Web 扩展:将 UI 组件插入页面

Mozilla Web Extensions: Insert UI component into page

我正在为 Firefox 编写一个 Web 扩展,它需要在使用某些 URL 检索的页面中插入大量附加功能。

借助 Mozilla 网站上的教程,我能够快速创建一个内容脚本,只要打开某个页面就会调用该脚本,但现在我无法真正将 html 片段插入页面.

我已经研究了几个小时了,但无济于事。这是我考虑和尝试过的:

  1. iframe 不起作用,因为显然某些安全策略不允许使用指向本地资源的 iframe,最后一条评论 here 甚至告诉我应该使用 panel 而不是 iframe
  2. 使用 Panel 对我不起作用有两个原因:
    • 我找不到使用我自己的自定义代码打开面板的方法(上面 link 的示例因 ReferenceError: require is not defined 而失败)
    • 我猜我只能通过使用 bowserAction 在 Web 扩展中打开一个面板,但是当我在页面本身需要它时,这会将按钮放在工具栏上
    • 根据文档,我只能为整个浏览器打开一个 Panel 实例,它会在与任何其他浏览器元素交互时自动关闭
  3. 最后我想过从打包到扩展中的资源文件中加载 html 并使用 innerHTML 将其送入页面,但我找不到要加载的任何 API来自资源的文本
  4. 仅使用 DOM API 对我不起作用,因为用代码创建所有元素需要很长时间

真不敢相信我这么久都没有注意到它,但我终于让它按照我的需要工作了。在这样做的同时,我什至想出了一个替代方法,所以这里开始。

但首先这是我拒绝使用 iframe 之外所有其他可能方法的主要原因:

  • 我需要通过扩展添加的 UI 元素来使用它们自己的 UI 样式,并且想利用现代框架(例如 jQuery 和 Bootstrap)并且我不想 运行 陷入 CSS 和 JavsScript 冲突的问题。 我实际上很早就注意到我要嵌入的页面中的 CSS 会覆盖 Bootstrap 样式。
  • 最好我也不想影响我嵌入的页面的百年标记。

选项 A - 带有外部源文件的 IFRAME

最后发现我唯一缺少的是 manifest.json 中的 web_accessible_resources 设置。一旦我将用作 iframe 源的 html 文件添加到该列表中,它就开始工作了。

// manifest.json:
{
    "manifest_version": 2,
    ...
    "web_accessible_resources": [
        "data/my.html"
    ],
    "content_scripts": [
        {
            "matches": ["*://*"],
            "js": ["js/my.js"]
        }
    ]
}

// js/my.js
var addonFrame = document.createElement ("IFRAME");
addonFrame.style = "position: absolute; bottom: 0; right: 0; width: 150px; height: 38px;";
addonFrame.frameBorder = "0";
addonFrame.src = chrome.extension.getURL ("data/my.html");
document.body.appendChild (addonFrame);

选项 B - 在 JS 中使用内联 HTML 的 IFRAME

在我最终使第一种方法起作用之前,我的实验引导我采用另一种可行方法 - 将 HTML 直接插入内容脚本中的 iframe

// js/my.js
var addonFrame = document.createElement ("IFRAME");
addonFrame.style = "position: absolute; bottom: 0; right: 0; width: 150px; height: 38px;";
addonFrame.frameBorder = "0";

var addonHtml = "<!DOCTYPE html>\n\
<html>\n\
    <head>\n\
        <meta charset='UTF-8'>\n\
        <title>Title of the document</title>\n\
    </head>\n\
    <body>\n\
        ...\n\
    </body>\n\
</html>";

addonFrame.src = 'data:text/html;charset=utf-8,' + encodeURI (addonHtml);
document.body.appendChild (addonFrame);

尽管我最终选择了选项 A,但让我概述一些利弊:

  1. 选项 A 显然更规范:视图 (html) 与行为 (js) 明显分开,所有文件都有适合其类型的内容(除了构建 iframe 元素的小例外在 JS 中)。 所以应该更容易支持前进。
  2. 选项 A 不允许在框架中使用内联脚本 (https://developer.chrome.com/extensions/contentSecurityPolicy)。这使得原型制作更加困难,但最终应该是一个加号。
  3. 出于某种我仍然不清楚的原因,我无法在选项 B 中插入的 html 中使用 #
  4. 选项 B 使得从附加框架到原始服务器的 ajax 调用更容易,因为框架源被认为来自与原始网页相同的域。 在选项 A 中,我不得不在框架中使用 Window.postMessage 来要求插入原始页面的内容脚本发出 ajax 请求并返回响应(第二部分特别难因为那里没有 jQuery 或 Prototype 之类的东西。