这是否足够安全,可以天真地打电话给chrome.tabs.executeScript每个
点击扩展图标的时间?换句话说,这是
幂等的?
- 是的,除非您的内容脚本修改了页面的 DOM 并且重新加载了扩展程序(通过设置页面重新加载它,通过更新等)。在这种情况下,您的旧内容脚本将不再在扩展程序的上下文中运行,因此它不能使用扩展程序 API,也不能直接与您的扩展程序通信。
chrome.tabs.insertCSS有类似的方法吗?
- 不,
chrome.tabs.insertCSS 没有包含保护。但是再次插入相同的样式表并不会改变页面的外观,因为所有规则都具有相同的 CSS 特异性,并且在这种情况下最后一个样式表优先。但是,如果样式表与您的扩展紧密耦合,那么您可以简单地使用 executeScript 注入脚本,检查它是否是第一次注入,如果是,则插入样式表(参见下面的示例)。
后台脚本检查注入状态的更好方法
内容脚本,所以我可以阻止调用
chrome.tabs.executeScript每次点击图标的时候?
- 您可以向选项卡 (
chrome.tabs.sendMessage) 发送消息,如果您没有收到回复,则假定选项卡中没有内容脚本并插入内容脚本。
2 的代码示例
在您的弹出/后台脚本中:
chrome.tabs.executeScript(tabId, {
file: 'contentscript.js',
}, function(results) {
if (chrome.runtime.lastError || !results || !results.length) {
return; // Permission error, tab closed, etc.
}
if (results[0] !== true) {
// Not already inserted before, do your thing, e.g. add your CSS:
chrome.tabs.insertCSS(tabId, { file: 'yourstylesheet.css' });
}
});
使用contentScript.js,您有两种解决方案:
- 直接使用windows:不推荐,因为每个人都可以改变那个变量和Is there a spec that the id of elements should be made global variable?
- 使用 chrome.storage API:您可以与其他窗口共享 contentScript 的状态(您可以看到缺点,这根本不是缺点,是您需要请求
Manifest.json 的权限。但这没关系,因为这是正确的方法。
选项 1: contentscript.js:
// Wrapping in a function to not leak/modify variables if the script
// was already inserted before.
(function() {
if (window.hasRun === true)
return true; // Will ultimately be passed back to executeScript
window.hasRun = true;
// rest of code ...
// No return value here, so the return value is "undefined" (without quotes).
})(); // <-- Invoke function. The return value is passed back to executeScript
注意,明确检查window.hasRun 的值很重要(上面示例中的true),否则它可能是具有id="hasRun" 属性的DOM 元素的自动创建的全局变量,请参阅Is there a spec that the id of elements should be made global variable?
选项 2: contentscript.js(使用 chrome.storage.sync 你也可以使用 chrome.storage.local)
// Wrapping in a function to not leak/modify variables if the script
// was already inserted before.
(chrome.storage.sync.get(['hasRun'], (hasRun)=>{
const updatedHasRun = checkHasRun(hasRun);
chrome.storage.syn.set({'hasRun', updatedHasRun});
))()
function checkHasRun(hasRun) {
if (hasRun === true)
return true; // Will ultimately be passed back to executeScript
hasRun = true;
// rest of code ...
// No return value here, so the return value is "undefined" (without quotes).
}; // <-- Invoke function. The return value is passed back to executeScript