缺少加载问题是您的manifest.json文件的JSON中有多个语法错误。在您的manifest.json文件中,文件末尾的行:
"default_title": "Call StickMan",
},
}
不应该有额外的,
(这表明您将在Object中拥有另一个属性):
"default_title": "Call StickMan"
}
}
如果您使用的是Firefox 开发者版,那么您有这些错误的事实将是显而易见的:
![FF 开发版 WebExtension 加载错误](https://i.stack.imgur.com/wV6yz.png)
但是,即使您运行的是 Firefox 47.0.1 并且仅使用了浏览器控制台(键盘快捷键:Ctrl- Shift- J),如评论中所建议的,您也会看到错误:
A promise chain failed to handle a rejection. Did you forget to '.catch', or did you forget to 'return'?
See https://developer.mozilla.org/Mozilla/JavaScript_code_modules/Promise.jsm/Promise
Date: Sun Jul 17 2016 11:11:22 GMT-0700 (Pacific Standard Time)
Full Message: SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
Full Stack: readJSON/</<@resource://gre/modules/Extension.jsm:628:19
NetUtil_asyncFetch/<.onStopRequest@resource://gre/modules/NetUtil.jsm:128:17
虽然有点神秘,但它仍然显示了第一个问题的行号:
Full Message: SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
Firefox Developer Edition 的浏览器控制台中产生的错误更容易解析到问题所在:
SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
Stack trace:
readJSON/</<@resource://gre/modules/Extension.jsm:859:19
NetUtil_asyncFetch/<.onStopRequest@resource://gre/modules/NetUtil.jsm:128:17
WebExtensions 开发:
WebExtensions API目前正在开发中。如果您正在开发 WebExtension,您应该使用Firefox Nightly或Firefox Developer Edition来测试您的代码。
更多关于你的代码:
语法错误:
除了上述语法错误之外,您还有更多问题。我并没有尝试解决所有这些问题,但确实被吸引到足够的修复中,以使附加组件能够正常工作。下一个报告的错误是语法错误,位于代码上的StickManUpdate.js文件中:
browser.tabs.sendMessage(
message: "End";
);
您在这里有多个问题。请参阅tabs.sendMessage() 文档。您缺少必需的tabId
参数。此外,您似乎混淆了将Object作为参数传递(包含传递给方法的信息的属性)与传递给方法的其他本机类型的参数列表之间的区别。注意:同时存在各种本地或非本地类型的参数列表和包含属性的对象并不少见,这些属性是传递给方法的数据。
假设browserAction
已定义:
您browserAction
在应该在的多个位置使用方法browser.browserAction
。browserAction
本身没有定义。或者,您可以browserAction
通过将其定义为:var browserAction = browser.browserAction;
.
使用browserAction.getTitle()
好像它是同步的,而实际上它是异步的:
您调用 以browserAction.getTitle()
获取标题的值。标题的值仅在您不提供的回调函数中可用。这意味着缺乏对异步编程的理解。您可能想查看有关该主题的一些问题,例如:
提供给的参数类型错误browserAction.setTitle()
:
这似乎再次混淆了其他本机类型的参数和作为对象(可能是对象文字)的参数之间的区别,该参数包含传递给方法的信息的属性. 诚然,在将信息传递给方法时,WebExtensions 似乎几乎任意混合使用实际参数和对象以及用作参数的属性。似乎需要小心在特定方法中使用哪个。
没有各种功能指定选项卡的 ID:
在对各种方法的多次调用中,您没有传递tabId
您应该传递的时间。您StickMan
canvas
每次单击鼠标都会将您的标签添加到单个选项卡中。您应该将选项卡 ID 传递给多个方法的调用。
document.body.innerHTML
在stickman.js中赋值:
一般来说innerHTML
,如果可能的话,应该避免在任何时候赋值。在大多数情况下,这是一个坏主意。在大多数情况下,它可能会导致重新评估整个 DOM。为了做你想做的事,在元素的 HTML 末尾添加文本格式的 HTML 到 DOM,有一个更好/更快的特定功能:insertAdjacentHTML()
. 你的代码:
document.body.innerHTML+= '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>';
可以写成:
document.body.insertAdjacentHTML("beforeend", '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>');
但是,在这里使用它仍然是一个坏主意insertAdjacentHTML()
。insertAdjacentHTML()
使用其中之一或分配给有一个重大的耻辱innerHTML
。使用其中任何一个都会导致您的附加组件在提交给 AMO 进行分发时受到额外的审查。这主要是因为使用任何一种方法来更改 DOM 都存在真正的安全问题。安全问题是当添加的是从输入/数据动态生成的文本时,这些文本没有硬编码到您的附加组件中。此外,您已经在混合添加元素作为文本并使用其他 JavaScript 对其执行更改(例如分配给canvas.style.position
)。你真的应该使用其中一个。在这种情况下,最好构造canvas
完全在 JavaScript 中。毕竟,在用于innerHTML
分配和getElementById()
查找canvas
元素的两行中,只需 4 行即可完成与您所做的相同的事情。
就个人而言,我喜欢insertAdjacentHTML()
在许多情况下使用复杂结构。使用它来插入大量 HTML 通常更快。它还允许您将插入的内容保留为文本。这样的文本可能更容易可视化添加的结构,而不是弄清楚一大块 DOM 使用生成的document.createElement()
和setAttribute()
实际的样子。然而,除了上面提到的其他缺点之外,使用insertAdjacentHTML()
可能并不容易编写模块化代码。
插入内容脚本的方式和问题canvas
:
每次用户单击 browserAction 按钮时,您都会将内容脚本的另一个副本插入选项卡。这会导致由于使用的内容脚本获取您的调用发送的消息browser.tabs.sendMessage()
而无法找到canvas
. 正确的解决方案是仅chrome.tabs.executeScript()
在第一次单击选项卡中的按钮时,然后每次在该选项卡中单击按钮时向内容脚本发送一条消息,从而将相同的按钮canvas
重新插入到 DOM 中。跟踪您是否已经将 StickMan 加载到特定选项卡中的一种简单方法是使用setTitle()
在该选项卡中第一次运行后使按钮的标题不同。
其他问题:
注意:stickman.js中的代码结构有点复杂。你可能想解决这个问题。
全部一起
清单.json:
{
"description": "Adds a stickfigure",
"manifest_version": 2,
"name": "StickMan",
"version": "1.0",
"icons": {
"48": "icons/StickMan-48.png"
},
"applications": {
"gecko": {
"id": "extention@stick.man",
"strict_min_version": "45.0"
}
},
"permissions": [
"activeTab"
],
"background": {
"scripts": ["StickManUpdate.js"]
},
"browser_action": {
"default_icon": {
"48": "icons/StickManButton.png"
},
"default_title": "Call StickMan",
"browser_style": true
}
}
StickManUpdate.js:
browser.browserAction.onClicked.addListener(function(tab) {
browser.browserAction.getTitle({tabId:tab.id},function(title){
if(title === 'Call StickMan') {
chrome.tabs.executeScript(tab.id, {
file: "/content_scripts/stickman.js"
});
browser.browserAction.setTitle({title:'Recall StickMan',tabId:tab.id});
} else if (title === 'Call StickMan again') {
browser.tabs.sendMessage(tab.id,"Draw");
browser.browserAction.setTitle({title:'Recall StickMan',tabId:tab.id});
}else {
browser.tabs.sendMessage(tab.id,"End");
browser.browserAction.setTitle({title:'Call StickMan again',tabId:tab.id});
}
});
});
火柴人.js:
var running = true;
//document.body.insertAdjacentHTML("beforeend", '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>');
var canvas = document.createElement("canvas");
canvas.setAttribute("width",100);
canvas.setAttribute("height",200);
//var canvas = document.getElementById('StickManCanvas0000000');
canvas.style.position = 'fixed';
canvas.style.left = '0px';
canvas.style.top = (window.innerHeight-200)+'px';
canvas.style.backgroundColor = 'rgba(0, 0, 0, 0)';
canvas.style.border = '1px dashed red';
var ctx = canvas.getContext('2d');
var pos = {
x:0,
headX:50,
headY:20,
bodyX:50,
bodyY:150,
leftArmX:25,
leftArmY:90,
rightArmX:75,
rightArmY:90,
leftLegX:30,
leftLegY:200,
rightLegX:70,
rightLegY:200,
};
var setPos = function(x, y) {
canvas.style.left = x+'px';
canvas.style.top = (window.innerHeight-y-200)+'px';
};
var drawMan = function(time) {
setPos(pos.x, 0);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 5;
ctx.beginPath();
ctx.arc(pos.headX, pos.headY, 20, 0, Math.PI*2, false);
ctx.moveTo(pos.headX, pos.headY);
ctx.lineTo(pos.bodyX, pos.bodyY);
ctx.lineTo(pos.rightLegX, pos.rightLegY);
ctx.moveTo(pos.bodyX, pos.bodyY);
ctx.lineTo(pos.leftLegX, pos.leftLegY);
ctx.moveTo((pos.bodyX+pos.headX)/2, ((pos.bodyY+pos.headY)/5)*2);
ctx.lineTo(pos.rightArmX, pos.rightArmY);
ctx.moveTo((pos.bodyX+pos.headX)/2, ((pos.bodyY+pos.headY)/5)*2);
ctx.lineTo(pos.leftArmX, pos.leftArmY);
ctx.stroke();
ctx.fillStyle = '#888888';
ctx.beginPath();
ctx.arc(pos.headX, pos.headY, 20, 0, Math.PI*2, false);
ctx.fill();
if(running) {
window.requestAnimationFrame(drawMan);
}
};
drawMan();
document.body.appendChild(canvas);
browser.runtime.onMessage.addListener(function(m) {
if(m === 'End' && running === true) {
running = false;
document.body.removeChild(canvas);
} else if(m === 'Draw' && running === false) {
running = true;
document.body.appendChild(canvas);
}
});
功能演示 [注1:您必须导航到实际网页。注意2:弹出来告诉您 browser_action 按钮的标题是什么的工具提示没有被我用来创建以下.gif的程序捕获。注意3:我将该browser_style
属性添加到browser_action
您的manifest.json文件中。它是 Firefox 48 中的新功能。没有它,Firefox 将在加载插件时在浏览器控制台中发出警告。]:
![StickMan 功能演示](https://i.stack.imgur.com/RpBld.gif)