一尘不染

从Background.js在页面级执行代码并返回值

javascript

我有一个网页,其中包含自己的脚本和变量,我需要执行这些脚本和变量并从扩展程序的Background.js中检索返回值。

我了解(我认为!),为了与网页进行交互,必须通过chrome.tabs.executeScript或ContentScript完成此操作,但是因为代码必须在原始页面的上下文中执行(为了具有作用域)
(脚本和变量),则需要先将其注入页面。

到目前为止,这就是我所得到的…

网页代码 (我想与之交互):

<html>
<head>
<script>
    var favColor = "Blue";

    function getURL() {
      return window.location.href;
    }
</script>
</head>

<body>
    <p>Example web page with script content I want interact with...</p>
</body>
</html>

manifest.json

{
  // Extension ID: behakphdmjpjhhbilolgcfgpnpcoamaa
  "name": "MyExtension",
  "version": "1.0",
  "manifest_version": 2,
  "description": "My Desc Here",
  "background": {
    "scripts": ["background.js"]
  },  
  "icons": {
    "128": "icon-128px.png"
  },
  "permissions": [
    "background",
    "tabs",
    "http://*/",
    "https://*/",
    "file://*/",           //### (DEBUG ONLY)
    "nativeMessaging"
  ]
}

background.js

codeToExec = ['var actualCode = "alert(favColor)";',
                  'var script = document.createElement("script");',
                  ' script.textContent = actualCode;',
                  '(document.head||document.documentElement).appendChild(script);',
                  'script.parentNode.removeChild(script);'].join('\n');
chrome.tabs.executeScript( tab.id, {code:codeToExec}, function(result) {
   console.log('Result = ' + result);
} );

我意识到代码当前只是在“更改”
favColor变量(这只是一项测试,以确保我可以看到它正常工作)。但是,如果我尝试返回该变量(通过将其保留为最后一条语句或说“ returnfavColor”),则executeScript回调将永远没有该值。

因此,这里似乎有(至少)三个级别:

  1. background.js
  2. 内容脚本
  3. 实际网页 (包含脚本/变量)

…我想知道从1级到3级(以上)并返回值的推荐方法是什么?

在此先感谢:o)


阅读 778

收藏
2020-05-01

共1个答案

一尘不染

您完全理解3层上下文分离。

  • 背景页面是一个单独的页面,因此不会与可见页面共享JS或DOM。
  • 内容脚本与网页的JS上下文隔离,但共享DOM。
  • 您可以使用共享DOM将代码注入页面的上下文中。它可以访问JS上下文,但不能访问Chrome API。

为了进行通信,这些层使用不同的方法:

*通过Chrome API进行 *背景 <->内容交流。
最原始的是的回调executeScript,但除了单行代码外,这对于任何其他情况都是不切实际的。
常用的方法是使用Messaging。
不常见,但可以使用chrome.storage及其onChanged事件进行通信。

页面 <->扩展名不能使用相同的技术。
由于注入的页面上下文脚本在技术上与页面本身的脚本没有什么区别,因此您正在寻找一种与扩展程序对话的网页方法。有两种可用的方法:

  1. 尽管页面对chrome.*API的访问非常非常有限,但它们仍可以使用消息传递来联系扩展。这是通过"externally_connectable"方法实现的。

好处是直接与扩展程序对话,但缺点是 需要从中专门将您正在使用的域白名单加入白名单
,并且您需要跟踪扩展名ID(但是由于要注入代码,因此您可以提供带有ID的代码)。如果需要在任何域上使用它,则不合适。

  1. 另一个解决方案是使用DOM事件。由于DOM在内容脚本和页面脚本之间共享,因此由一个人生成的事件将对另一个人可见。

该文档演示了如何使用window.postMessage此效果。从概念上讲,使用自定义事件更为清晰。

这种方法的缺点是 要求内容脚本充当代理 。这些脚本中必须包含以下内容:

    window.addEventListener("PassToBackground", function(evt) {
  chrome.runtime.sendMessage(evt.detail);
}, false);

而后台脚本使用chrome.runtime.onMessage侦听器对此进行处理。

我建议您编写一个单独的内容脚本,并executeScript使用file属性而不是进行调用code,而不要依赖其回调。消息传递更加简洁,可以多次将数据返回到后台脚本。

2020-05-01