【问题标题】:PageMod attaching worker to same URL multiple timesPageMod 多次将工作人员附加到同一个 URL
【发布时间】:2014-03-13 14:45:18
【问题描述】:

找到干净的解决方案

我找到了一个非常干净的解决方案,它确实使整个问题变得毫无意义,当我问这个问题时,我确信它存在......我也太无知了。

PageMod 构造函数中使用attachTo: 'top' 只会将脚本附加到顶级文档,而不是任何iframes

因此,如果您发现 PageMod 为您的附加组件附加了多次,这可能是由于它与顶级选项卡文档一起附加到 iframes。添加attachTo: 'top' 作为传递给PageMod 构造函数的对象的属性,您无需担心iframes

对于下面的问题,解决方案是

var _workers = [];

var pageMod = require("sdk/page-mod").PageMod({
    include: /https?:\/\/www\.websitename\.net.*/,
    contentScript: "self.port.on('hello', function() { " +
                   "console.log('['+document.location.href+']: " +
                   "My worker said hello to me!');",
    contentScriptWhen: "end",
    attachTo: 'top',   //<-- add this property to only attach to top level document
    onAttach: function(worker) {
        _workers.push(worker);
        worker.on("detach", function() {
            var ind = _workers.indexOf(this);
            if(ind !== -1) {
                _workers.splice(ind, 1);
            }
        });
        worker.port.emit("hello");
    }
});

当然,如果没有@Noitidart 的帮助,我永远无法确定成为iframes 的原因。

老问题

我正在尝试为 Firefox 编写一个插件来修改特定网站的页面。我认为PageMod 是完美的选择,但我遇到了一些问题。工作人员似乎多次(4 到 2 次)附加到同一个 URL,我不知道为什么会发生这种情况。

我在插件的ma​​in.js中尝试了以下代码:

var _workers = [];

var pageMod = require("sdk/page-mod").PageMod({
    include: /https?:\/\/www\.websitename\.net.*/,
    contentScript: "self.port.on('hello', function() { " +
                   "console.log('['+document.location.href+']: " +
                   "My worker said hello to me!');",
    contentScriptWhen: "end",
    onAttach: function(worker) {
        _workers.push(worker);
        worker.on("detach", function() {
            var ind = _workers.indexOf(this);
            if(ind !== -1) {
                _workers.splice(ind, 1);
            }
        });
        worker.port.emit("hello");
    }
});

在运行此代码并在一个单独的选项卡中打开 https://www.websitename.net 时,控制台有 2 到 4 个实例

[https://www.websitename.net/]: My worker said hello to me!

这意味着同一个页面有多个附加到它的工作人员。 我不知道为什么会这样,我当然不希望这样,因为我打算稍后使用 _workers 数组与附加的脚本进行通信。

编辑

感谢@Noitidart,我现在已经确认在多个工作人员中,只有一个是实际页面,其他是 iframe,这就是每个工作人员的内容脚本可用的 DOM 内容不同的原因。

不过,问题仍然存在。如何确保工作人员(以及内容脚本)不附加到 iframe?

我可以确保未附加到 iframe 的工作人员是推送到 _workers 的工作人员,但是一旦我确保内容脚本是正确的,有没有办法将内容脚本附加到工作人员一?我不希望多次附加相当大的内容脚本。

编辑 2

再次感谢@Noitidart,我想我有一些解决方案:如果检测到工人被附加到iframe,则销毁。

更好的解决方案是仅将主要内容脚本附加到正确的工作人员,但目前我无法找到将内容脚本附加到正确工作人员的方法(worker.contentScriptFile = data.url("file.js") 似乎不起作用) .

所以,当前的 hack:

verify.js

if(window.top !== window) {
    self.port.emit('iframe');
}
else {
    self.port.emit('hi');
}

ma​​in.js

var _workers = [];

var pageMod = require("sdk/page-mod").PageMod({
    include: /https?:\/\/www\.websitename\.net.*/,
    contentScriptFile: [data.url("verify.js"), data.url("my_main_script.js")],
    contentScriptWhen: "end",
    onAttach: function(worker) {
        worker.on("detach", function() {
            var ind = _workers.indexOf(this);
            if(ind !== -1) {
                _workers.splice(ind, 1);
            }
        });

        worker.port.on("hi", function() {
            //Not iframe, keep this one.
            //If there is a way, attach 'my_main_script.js'
            //to this worker now, and not before.

            _workers.push(worker);

            //Emit 'ack' to tell my_main_script.js
            //that we're good to go.
            worker.port.emit('ack');
        });

        worker.port.on("iframe", function() {
            //iframe, get rid of it.
            worker.destroy();
        });
    }
});

我应该注意,脚本出现在contentScriptFile 中的顺序无关紧要,两个脚本都会为每个附件加载。所以希望 verify.jsmy_main_script.js 加载之前销毁工作人员是没有意义的。

同样,这个解决方案并不完整。如果我在这一点上没有足够强调,我真的希望有一种方法可以将 my_main_script.js 附加到正确的工作人员,而不是让所有工作人员都加载它。如果有这种方法,请评论/回答。

【问题讨论】:

  • 您的文档中有 iframe 吗?他们也可能会依附于此。
  • @Noitidart 实际上,是的。并且文档中 iframe 的数量似乎与工人被附加的次数相对应。不错的收获!有没有办法阻止脚本附加到 iframe?
  • +1 分享解决方案谢谢
  • 我无法告诉您我多么感谢您分享了解决方案。我差点被那个错误发疯。非常感谢,伙计!

标签: javascript firefox firefox-addon firefox-addon-sdk


【解决方案1】:

在 contentScript 或网站中运行的任何内容中(我对 sdk 了解不多),检查 if (window.frameElement == true) 如果它的真值比它的框架那么你想取消附加。

编辑: 也许 window.frameElement 不会在框架内工作。如果它不起作用,请执行此操作if (window.top != window) 然后它是一个框架

【讨论】:

  • 当我检测到iframe(使用window!==window.top)时,我没有考虑过像调用worker.destroy() 这样简单的事情。谢谢你的帮助!我真的很感激。
  • 你能分享一下工人的工作方式还是什么,所以我知道将来当我帮助插件 sdk 用户时。谢谢
  • 还请分享您的最终简化代码,以便其他人也可以受益:) 这些主题是我了解 sdk 的地方。大声笑
  • 我正在快速检查一些事情,并试图看看哪个是最优化的解决方案。现在,它正在摧毁附加到 iframe 的工人。但我宁愿找到一种方法,使主要内容脚本根本不附加到这些工作人员身上。我会在几分钟后用最合适的代码编辑我的问题。
【解决方案2】:

这是Mozilla documentation 的链接,您可以使用 attachTo 设置。 'all' 的默认设置包括 iframe,因此您应该执行以下操作

var pageMod = require("sdk/page-mod");
  pageMod.PageMod({
  include: "*",
  contentScript: "",
  attachTo: ["existing", "top"],
  onAttach: function(worker) {
   console.log(worker.tab.url);
 }
});

【讨论】:

  • 这解决了我的问题,页面在内容中加载 iframe,并且每次 iframe 完成加载时都会调用我的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-19
  • 1970-01-01
  • 2016-10-08
相关资源
最近更新 更多