Chrome扩展程序代码 vs 内容脚本 vs 插入脚本

65

我正在尝试让我的Chrome扩展在每次加载新页面时运行init()函数,但我很难理解如何实现。据我所知,我需要在background.html中执行以下操作:

  1. 使用chrome.tabs.onUpdated.addListener()检查页面何时发生更改
  2. 使用chrome.tabs.executeScript运行脚本。

这是我目前的代码:

//background.html
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    chrome.tabs.executeScript(null, {code:"init();"});
});

//script.js
function init() {
    alert("It works!");
}

我也想知道init()函数是否可以访问其他JS文件中的函数?

1个回答

174

Chrome扩展中的JavaScript代码可以分为以下几类:

  • 扩展程序代码 - 可以完全访问所有允许的chrome.* APIs。
    这包括后台页面和所有通过chrome.extension.getBackgroundPage()直接访问它的页面,例如浏览器弹出窗口

  • 内容脚本(通过清单文件或chrome.tabs.executeScript)- 对一些chrome API的部分访问权限,对页面的DOM具有完全访问权限(不包括任何window对象,包括框架)。
    内容脚本在扩展和页面之间的作用域中运行。内容脚本的全局window对象与页面/扩展的全局命名空间不同。

  • 注入脚本(通过内容脚本中的这种方法)- 可以完全访问页面中的所有属性。无法访问任何chrome.* APIs。
    注入的脚本行为就像它们是页面本身包含的一样,并且与扩展没有任何连接。请参见此帖子了解有关各种注入方法的更多信息。

要从注入的脚本发送消息到内容脚本,必须使用事件。有关示例,请参见此答案。注意:在扩展程序内部从一个上下文传输的消息会自动(JSON)序列化和解析


在您的情况下,后台页面的代码(chrome.tabs.onUpdated)可能会在内容脚本script.js被评估之前调用。所以,您将获得一个ReferenceError,因为init未定义。

此外,当使用chrome.tabs.onUpdated时,请确保测试页面是否完全加载,因为该事件会触发两次:在加载之前和完成后:

//background.html
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (changeInfo.status == 'complete') {
        // Execute some script when the page is fully (DOM) ready
        chrome.tabs.executeScript(null, {code:"init();"});
    }
});

2
谢谢你提供关于 chrome.tabs.onUpdated 会触发两次的提示。那么我的问题是,我应该如何注入 init() 呢?我应该注入所有的 JavaScripts 吗?通常当用户点击浏览器操作图标时,init() 会被调用,并触发一系列其他函数。 - Jon
1
当需要访问页面的全局变量时,请注入脚本。 当 init函数 需要访问页面和扩展代码时,请使用内容脚本。 请参见 链接答案 以了解如何注入脚本,以及 此答案 来了解如何实现需要访问页面变量的内容脚本的指南。 - Rob W
嗨@RobW,我有一个问题。就性能或处理而言,它们都没有任何区别。如果我必须处理一些大型脚本,哪个地方更适合进行后台或内容脚本?或者两种方式都可能会出现一些漏洞? - pvnarula
2
如果它是 CPU 密集型的,请考虑在后台页面中使用 Worker。如果有一个昂贵的一次性初始化步骤,请使用后台脚本。另一方面,如果存在特定于选项卡/页面的代码,例如严重依赖于 DOM(并且后台页面的响应能力很重要),则应使用内容脚本,因为在一个选项卡中执行 JavaScript 不会干扰另一个选项卡,而将其放在后台页面会阻止扩展程序的后台脚本响应其他事件。 - Rob W
对于 chrome.tabs.executeScriptconsolelocalStorage 可以使用,尽管它们是全局窗口对象。但是应用程序在窗口命名空间中定义的对象(例如 window.ContextHub = window.ContextHub || {};)则不行。是否有允许的白名单集合和不允许的黑名单集合? - Sandeep Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接