我正在创建一个扩展程序,我需要能够在单击页面操作按钮时多次运行内容脚本。我在我的background.js中有这个:
chrome.pageAction.onClicked.addListener(function(tab) {
alert('calling content_script');
chrome.tabs.executeScript(null, {
file: 'content_script.js'
},function(){alert("success");});
});
这是第一次单击按钮时有效。当第二次点击时,我得到我的弹出窗口“调用content_script”,但内容脚本永远不会被执行。这是为什么?
以下是完整的背景脚本:
function checkForValidUrl(tabId, ChangeInfo, tab){
if(tab.url.indexOf("tiger.armstrong")> -1){
chrome.pageAction.show(tabId);
if(tab.url.indexOf("tiger.armstrong") == 0){
chrome.pageAction.hide(tabId);
}
}
}
chrome.tabs.onUpdated.addListener(checkForValidUrl);
chrome.pageAction.onClicked.addListener(function(tab) {
alert('calling content_script');
chrome.tabs.executeScript(null, {
file: 'content_script.js'
},function(){alert("success");});
});
这是清单:
{
"name": "LiveLab Post Grades",
"version": "2.0",
"permissions": [
"activeTab","tabs","http://*/*","https://*/*"
],
"background": {
"scripts": ["jquery.min.js","background3.js"],
"persistent": false
},
"page_action": {
"default_icon": {
"19": "GIcon.png"
},
"default_title": "LiveLab Tools"
},
"content_scripts": [ {
"js": [ "jquery.min.js" ],
"matches": [ "http://*/*", "https://*/*"],
"run_at": "document_end"
}],
"manifest_version": 2
}
以下是内容脚本:
var livelabtools = {
/**
* this function is like window.open, but it can POST (rather than GET) from js
* source: http://canop.org/blog/?p=426
*/
canop_open: function (verb, url, data, target) {
var form = document.createElement("form");
form.action = url;
form.method = verb;
form.target = target || "_self";
if (data) {
//for (var key in data) {
var input = document.createElement("input");
input.name = 'data';
input.value = data;//typeof data[key] === "object" ? JSON.stringify(data[key]) : data[key];
form.appendChild(input);
//console.log(form);
//}
}
// these two lines are only needed for ie
//form.style.display = 'none';
//document.body.appendChild(form);
form.submit();
console.log("form submit === " + form);
form.remove();
},
post_grades: function () {
alert('in post grades!!!!');
var str, exercise,
i = 0;
grades = {};
do {
ex_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc3:st3";
lname_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc1:st1";
grade_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc7:st7_field";
exercise = document.getElementById(ex_str);
lname = document.getElementById(lname_str);
grade = document.getElementById(grade_str);
if (exercise != null) {
if (grades[lname.innerHTML] === undefined)
grades[lname.innerHTML] = {};
console.log(lname.innerHTML + ", " + exercise.innerHTML + ", " + grade.innerHTML);
if (grade.value != null && grade.value != '')
grades[lname.innerHTML][exercise.innerHTML] = grade.value;
else
grades[lname.innerHTML][exercise.innerHTML] = "0";
}
i++;
} while (exercise != null);
// console.log(JSON.stringify(grades));
// console.log(JSON.stringify(grades).length)
//window.open("http://aspen2.cscofc.info/jsontocsv.php?data="+JSON.stringify(grades));
console.log('posting...' + "\n JSON.String... = "+ JSON.stringify(grades));
livelabtools.canop_open("post", "http://aspen2.cscofc.info/jsontocsv.php", JSON.stringify(grades));
console.log('done');
return "function end";
}
}
console.log(livelabtools.post_grades());
除非被问到,否则我不会详细介绍它,但需要注意的重要部分是return语句和控制台日志。第一次单击页面操作按钮时,一切都运行得很好,完成后,我将“功能结束”打印到控制台。然而,在初始运行之后,每当我点击页面操作按钮时,我都会收到一条提示“调用content_script”的警报,而没有其他任何事情发生。为什么我的内容脚本不会多次运行?
答案 0 :(得分:2)
似乎已经注入了一个脚本,它不再被注入 因此,可行的方法是通过将消息传递给内容脚本来启动您的操作。 (当然,如果尚未注入内容脚本,则需要先注入它。)
我提出的一个解决方案(经过测试证实它工作正常)如下:
在pageAction.onClicked
上,从背景页面向内容脚本发送消息,要求其执行某些操作(例如,发布成绩)。另外,请求将回复发送回背景页面
[另见 chrome.tabs.sendMessage(...) 。]
如果已经注入了内容脚本,请让它收到消息,将确认信息发送回后台页面并继续执行某些操作(例如发布成绩)。这个过程可以根据需要进行多次 [另见 chrome.runtime.onMessage 。]
第一次触发pageAction.onClicked
时,将没有内容脚本侦听消息。在这种情况下,将不会有消息确认。而是设置 chrome.runtime.lastError 。在这种情况下,后台页面必须首先注入内容脚本,然后再次发送消息
[另见 chrome.runtime.lastError 。]
理论上说,应该这样做! 实际上,这是适用于我的示例代码:
<强>的manifest.json 强>: (注意:如果您对需要访问的页面有更多具体要求,可以将它们合并到清单中并删除一些权限。)
{
...
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"page_action": {
"default_title": "Test Extension"
},
"permissions": [
"tabs",
"http://*/*",
"https://*/*"
]
...
}
<强> background.js:强>
function checkForValidURL(tabId, info, tab) {
var idx = tab.url.indexOf("tiger.armstrong");
if (idx > 0) {
chrome.pageAction.show(tabId);
} else {
chrome.pageAction.hide(tabId);
}
}
chrome.tabs.onUpdated.addListener(checkForValidURL);
function onPageActionClicked(tab) {
// Send message to content script, asking to post grades
alert("Calling content_script...");
chrome.tabs.sendMessage(tab.id, { action: "postGrades" }, function() {
if (chrome.runtime.lastError) {
// The error indicates that the content script
// has not been injected yet. Inject it and...
chrome.tabs.executeScript(tab.id, {
file: "content.js"
}, function() {
if (!chrome.runtime.lastError) {
// ...if injected successfully, send the message anew
onPageActionClicked(tab);
}
});
} else {
// The content script called our response callback,
// confirming that it is there and got our message
alert("Message got through !");
}
});
};
chrome.pageAction.onClicked.addListener(onPageActionClicked);
<强> content.js:强>
var livelabtools = {
/**
* This function is like window.open, but it can POST (rather than GET) from
* JS source: http://canop.org/blog/?p=426
*/
canop_open: function (method, url, data, target) {
var form = document.createElement("form");
form.action = url;
form.method = method;
form.target = target || "_self";
// 'data' is an object with key-value pairs
// of fields to be sent
if (data) {
for (var key in data) {
var input = document.createElement("input");
input.name = key;
input.value = (typeof(data[key]) === "object")
? JSON.stringify(data[key]) : data[key];
form.appendChild(input);
}
}
form.submit();
form.remove();
},
post_grades: function () {
console.log("Posting some grades...");
livelabtools.canop_open("POST",
"http://aspen2.cscofc.info/jsontocsv.php",
"{}");
console.log("Grades sent !");
}
}
// Listen for messages from the background page
// (It actually listens for messages from anyone in the context,
// but the background page is the one that interrests us)
chrome.runtime.onMessage.addListener(function(msg, sender, response) {
// If we've been asked to post grades...
if (msg.action && (msg.action == "postGrades")) {
// ...confirm we got the message and...
response();
// ...do what we do best: post grades !
livelabtools.post_grades();
}
});
让我们希望这涵盖它:)