如何防止多个 injection/execution 内容脚本响应单个事件?
How can I prevent multiple injection/execution of content script(s) in response to a single event?
我正在构建一个 chrome 扩展来响应上下文菜单上的点击事件。
我的后台脚本使用 chrome.contextMenus.create
api 方法调用创建上下文菜单并设置点击处理程序,如下面的代码所示:
//event.js
function onItemClick(info, tab){
// Inject the content script into the current page
chrome.tabs.executeScript(null, { file: 'content.js' });
// Perform the callback when a message is received from the content script
chrome.runtime.onMessage.addListener(function(message){
var url = "data:text/html;charset=utf8,";
function append(key, value){
var input = document.createElement('textarea');
input.setAttribute('name', key);
input.textContent = value;
form.appendChild(input);
}
var form = document.createElement('form');
form.method = 'POST';
form.action = 'http://localhost/myapp/myapp.php';
form.style.visibility = "hidden";
append('url', message.url);
append('text', message.selectedText);
url = url + encodeURIComponent(form.outerHTML);
url = url + encodeURIComponent('<script>document.forms[0].submit();</script>');
chrome.tabs.create({url: url, active: true});
});
}
var context = "selection";
var title = "Share in new tab";
var id = chrome.contextMenus.create({"title": title, "contexts": [context], "onclick": onItemClick});
上面的后台脚本以编程方式创建一个自动在新选项卡中提交的表单。这样做时,它会调用下面的 "content script" 以从当前 page/tab.
中获取一些信息
//content.js
chrome.runtime.sendMessage({
'url': window.location.href,
'selectedText': window.getSelection().toString()
});
问题是这样的。后台脚本中的点击处理程序多次将 "content script" 注入当前页面(即每次调用点击处理程序时)。作为多次注入的结果,"content script" 的每个注入实例都会被执行,从而导致打开多个新的 tabs/pages。每次单击上下文菜单项时,打开的新选项卡数量都会增加一个,这表明问题确实是内容脚本的多次注入和执行。我怎样才能只注入一次内容脚本,或者至少确保只有一个 "instance" 注入的脚本将消息发送回我的后台脚本?
我曾尝试在清单中自动注入脚本,但此后调用 chrome.tabs.executeScript
会导致无休止地创建选项卡。所以,我真的需要能够按需注入脚本,但要找到一种方法来防止多次注入或至少确保只有一个 "injection" 发回消息。请帮忙!
解决方法很简单:可以在内容脚本中创建一个全局控制变量。在开始时检查它,如果是 undefined
则将其设置为 true
并继续。第一个执行的内容脚本将设置变量并防止其他人做任何事情。
顺便说一句,我看到您在另一个侦听器中向 chrome.runtime.onMessage
添加一个侦听器:这不是好的做法,因为它会为同一事件添加多个侦听器并导致多次执行它们.您应该改为在外部声明侦听器,发送一条不同的消息说 "do something" 或 "do something else".
在内容脚本中:
if (window.messageSent === undefined) {
window.messageSent = true;
chrome.runtime.sendMessage({
action: "submit the form",
url: window.location.href,
selectedText: window.getSelection().toString()
});
}
在background.js
:
chrome.runtime.onMessage.addListener(function(message){
if (message.action == "submit the form") {
// do what you need to submit the form
var url = "data:text/html;charset=utf8,";
function append(key, value){
...
}
});
我正在构建一个 chrome 扩展来响应上下文菜单上的点击事件。
我的后台脚本使用 chrome.contextMenus.create
api 方法调用创建上下文菜单并设置点击处理程序,如下面的代码所示:
//event.js
function onItemClick(info, tab){
// Inject the content script into the current page
chrome.tabs.executeScript(null, { file: 'content.js' });
// Perform the callback when a message is received from the content script
chrome.runtime.onMessage.addListener(function(message){
var url = "data:text/html;charset=utf8,";
function append(key, value){
var input = document.createElement('textarea');
input.setAttribute('name', key);
input.textContent = value;
form.appendChild(input);
}
var form = document.createElement('form');
form.method = 'POST';
form.action = 'http://localhost/myapp/myapp.php';
form.style.visibility = "hidden";
append('url', message.url);
append('text', message.selectedText);
url = url + encodeURIComponent(form.outerHTML);
url = url + encodeURIComponent('<script>document.forms[0].submit();</script>');
chrome.tabs.create({url: url, active: true});
});
}
var context = "selection";
var title = "Share in new tab";
var id = chrome.contextMenus.create({"title": title, "contexts": [context], "onclick": onItemClick});
上面的后台脚本以编程方式创建一个自动在新选项卡中提交的表单。这样做时,它会调用下面的 "content script" 以从当前 page/tab.
中获取一些信息//content.js
chrome.runtime.sendMessage({
'url': window.location.href,
'selectedText': window.getSelection().toString()
});
问题是这样的。后台脚本中的点击处理程序多次将 "content script" 注入当前页面(即每次调用点击处理程序时)。作为多次注入的结果,"content script" 的每个注入实例都会被执行,从而导致打开多个新的 tabs/pages。每次单击上下文菜单项时,打开的新选项卡数量都会增加一个,这表明问题确实是内容脚本的多次注入和执行。我怎样才能只注入一次内容脚本,或者至少确保只有一个 "instance" 注入的脚本将消息发送回我的后台脚本?
我曾尝试在清单中自动注入脚本,但此后调用 chrome.tabs.executeScript
会导致无休止地创建选项卡。所以,我真的需要能够按需注入脚本,但要找到一种方法来防止多次注入或至少确保只有一个 "injection" 发回消息。请帮忙!
解决方法很简单:可以在内容脚本中创建一个全局控制变量。在开始时检查它,如果是 undefined
则将其设置为 true
并继续。第一个执行的内容脚本将设置变量并防止其他人做任何事情。
顺便说一句,我看到您在另一个侦听器中向 chrome.runtime.onMessage
添加一个侦听器:这不是好的做法,因为它会为同一事件添加多个侦听器并导致多次执行它们.您应该改为在外部声明侦听器,发送一条不同的消息说 "do something" 或 "do something else".
在内容脚本中:
if (window.messageSent === undefined) {
window.messageSent = true;
chrome.runtime.sendMessage({
action: "submit the form",
url: window.location.href,
selectedText: window.getSelection().toString()
});
}
在background.js
:
chrome.runtime.onMessage.addListener(function(message){
if (message.action == "submit the form") {
// do what you need to submit the form
var url = "data:text/html;charset=utf8,";
function append(key, value){
...
}
});