我正在使用Firefox addon-sdk开发一个小扩展,它必须改变页面中DOM元素的内容。我正在使用PageMod
添加内容脚本并注册一些事件,其中一些我想传递一个回调函数,如下所示:
main.js
pageMod.PageMod({
include: "*",
contentScriptWhen: 'ready',
contentScriptFile: [self.data.url("my_content_script.js")],
onAttach: function(worker) {
worker.port.on("processElement", function(elementSrc, callback) {
doSomeProcessingViaJsctypes();
callback("http://someUrl/image.png");
});
}
});
my_content_script.js
var elements = document.getElementsByTagName("img");
var elementsLength = elements.length;
for (var i = 0; i < elementsLength; i++)
{
(function(obj) {
obj.setAttribute("data-processed", "true");
self.port.emit("processElement", obj.src, function(newSrc) {
console.log("replaced " + obj.src);
obj.src = newSrc;
});
})(elements[i]);
}
错误
TypeError: callback is not a function
Stack trace:
.onAttach/<@resource://gre/modules/XPIProvider.jsm -> file:///c:/users/sebast~1/appdata/local/temp/tmpjprtpo.mozrunner/extensions/jid1-gWyqTW27PXeXmA@jetpack/bootstrap.js -> resource://gre/modules/commonjs/toolkit/loader.js -> resource://jid1-gwyqtw27pxexma-at-jetpack/testextension/lib/main.js:53
我似乎无法在网上找到任何关于此事的内容。我需要这种方法,因为处理需要一些时间并依赖于.dll文件,因此我无法从内容脚本中调用它。
如果我要处理元素,那么在调用worker.port.emit()
之后我将不得不再次遍历整个树来识别元素并更改它的src
属性。这将花费很长时间,并为文档中的每个img
添加额外的循环。
我考虑过生成一个唯一的类名并将其附加到元素的类中,然后调用getElementsByClassName()
。我没有对此进行过测试,但在我看来,它需要的时间与上述过程相同。
任何建议都将不胜感激。
编辑:我在另一个问题上找到了this answer。 Wladimir Palant建议使用window-utils
获取activeBrowserWindow
,然后重复审核content
。
他还提到了
这些低级API并不保证稳定,而且window-utils模块甚至没有完整记录
此后有什么变化吗?我想知道您是否可以使用选项卡获取相同的content
属性,以及是否可以识别工作人员发送self.port.emit()
的选项卡。
答案 0 :(得分:2)
在内容脚本和模块(main.js
)之间使用消息传递时,只能传递JSON可序列化的数据。
传递<img>.src
应该没问题,因为这是一个字符串,因此JSON可序列化。
您的代码因您尝试传递的回调函数而中断,因为function
不 JSON可序列化(与整个DOM节点不是JSON可序列化相同)。
此外,.emit
和.on
仅使用第一个参数作为消息有效内容。
在进行处理后,您必须实际emit
将另一条消息返回到内容脚本,而不是回调。由于您无法传递DOM元素,因此您需要跟踪哪些DOM元素属于哪个消息。
好的,这是我如何做到的。
首先main.js
:
const self = require("sdk/self");
const {PageMod} = require("sdk/page-mod");
function processImage(src) {
return src + " dummy";
}
PageMod({
include: "*",
contentScriptWhen: 'ready',
contentScriptFile: [self.data.url("content.js")],
onAttach: function(worker) {
worker.port.on("processImage", function(data) {
worker.port.emit("processedImage", {
job: data.job,
newSrc: processImage(data.src)
});
});
}
});
在我的设计中,每条processImage
邮件都有job
与之关联(请参阅内容脚本),main.js
认为不透明,只是逐字回复回复。
现在,data/content.js
,又名。我的内容脚本:
var jobs = new Map();
var jobCounter = 0;
self.port.on("processedImage", function(data) {
var img = jobs.get(data.job);
jobs.delete(data.job);
var newSrc = data.newSrc;
console.log("supposed replace", img.src, "with", newSrc);
});
for (var i of document.querySelectorAll("img")) {
var job = jobCounter++; // new job number
jobs.set(job, i);
self.port.emit("processImage", {
job: job,
src: i.src
});
}
因此,对于每个图像,我们将创建一个作业编号(可能是一个uuid或其他任何代替,但递增一个计数器对我们的用例来说已经足够了),并将与该作业编号关联的DOM图像放入一个地图中跟踪它。
之后,只需将邮件发布到main.js
。
processedImage
处理程序,将收到工作号和新来源,使用工作号和jobs
地图获取DOM元素,再次将其从地图中删除(我们不会#39) ; t想泄漏它的东西)并做任何需要的处理;在这个例子中只记录东西。