从 Background.js 在页面级别执行代码并返回值 [英] Executing code at page-level from Background.js and returning the value

查看:27
本文介绍了从 Background.js 在页面级别执行代码并返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've got a web page with its own scripts and variables that I need to execute and retrieve return values from my extension's Background.js.

我明白(我认为!)为了与网页交互,必须通过 chrome.tabs.executeScript 或 ContentScript 来完成,但因为代码必须在原始页面的上下文中执行(按顺序)要具有脚本和变量的范围),则需要先将其注入页面.

I understand (I think!) that in order to interact with the web page, it must be done via chrome.tabs.executeScript or a ContentScript, but because the code must execute in the context of the original page (in order to have scope to the scripts and variables), it needs to be injected into the page first.

按照这个 Rob W 的精彩帖子,我可以调用页面级脚本/变量,但是我正在努力理解如何以这种方式返回值.

Following this great post by Rob W, I'm able to invoke the page-level script/variables, but I'm struggling to understand how to return values in this way.

这是我到目前为止所得到的......

Here's what I've got so far...

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

<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>

ma​​nifest.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('
');
chrome.tabs.executeScript( tab.id, {code:codeToExec}, function(result) {
   console.log('Result = ' + result);
} );

我意识到代码目前只是提醒"favColor 变量(这只是一个测试,以确保我可以看到它工作).但是,如果我尝试返回该变量(将其保留为最后一个语句或说返回 favColor"),则 executeScript 回调永远不会有该值.

I realise the code is currently just "alerting" the favColor variable (this was just a test to make sure I could see it working). However, if I ever try returning that variable (either by leaving it as the last statement or by saying "return favColor"), the executeScript callback never has the value.

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

So, there appear to be (at least) three levels here:

  1. background.js
  2. 内容脚本
  3. 实际网页(包含脚本/变量)
  1. background.js
  2. content scripts
  3. actual web page (containing scripts/variables)

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

...and I would like to know what is the recommended way to talk from level 1 to level 3 (above) and return values?

提前致谢:o)

推荐答案

您对 3 层上下文分离的理解非常正确.

You are quite right in understanding the 3-layer context separation.

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

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

To communicate, those layers use different methods:

背景 <-> 内容通过 Chrome API 交谈.
最原始的是 executeScript 的回调,但除了单行之外,它是不切实际的.
常用的方法是使用Messaging.
不常见,但可以使用 chrome.storage 及其 onChanged 事件进行通信.

Background <-> Content talk through Chrome API.
The most primitive is the callback of executeScript, but it's impractical for anything but one-liners.
The common way is to use Messaging.
Uncommon, but it's possible to communicate using chrome.storage and its onChanged event.

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

Page <-> Extension cannot use the same techniques.
Since injected page-context scripts do not technically differ from page's own scripts, you're looking for methods for a webpage to talk to an extension. There are 2 methods available:

  1. 虽然页面对 chrome.* API 的访问非常非常有限,但它们仍然可以使用 Messaging 来联系扩展程序.这是通过"externally_connectable"方法实现的.

  1. While pages have very, very limited access to chrome.* APIs, they can nevertheless use Messaging to contact the extension. This is achieved through "externally_connectable" method.

我最近详细描述了这个答案.简而言之,如果您的扩展程序声明允许域与其通信,并且域知道扩展程序的 ID,则它可以向扩展程序发送外部消息.

I have recently described it in detail this answer. In short, if your extension declared that a domain is allowed to communicate with it, and the domain knows the extension's ID, it can send an external message to the extension.

优点是直接与扩展程序对话,但缺点是要求将您正在使用它的域从白名单中特别列出,并且您需要跟踪您的扩展程序 ID(但由于您'正在注入代码,您可以提供带有 ID 的代码).如果您需要在任何域上使用它,这是不合适的.

The upside is directly talking to the extension, but the downside is the requirement to specifically whitelist domains you're using this from, and you need to keep track of your extension ID (but since you're injecting the code, you can supply the code with the ID). If you need to use it on any domain, this is unsuitable.

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

Another solution is to use DOM Events. Since the DOM is shared between the content script and the page script, an event generated by one will be visible to another.

文档演示了如何使用window.postMessage 为了这个效果;使用自定义事件在概念上更清晰.

The documentation demonstrates how to use window.postMessage for this effect; using Custom Events is conceptually more clear.

同样,我之前回答过这个问题.

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

The downside of this method is the requirement for a content script to act as a proxy. Something along these lines must be present in the content script:

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

而后台脚本使用 chrome.runtime.onMessage 侦听器处理它.

while the background script processes this with a chrome.runtime.onMessage listener.

我鼓励您编写单独的内容脚本并使用 file 属性而不是 code 来调用 executeScript,而不是依赖其回调.消息传递更清晰,允许多次将数据返回到后台脚本.

I encourage you to write a separate content script and invoke executeScript with a file attribute instead of code, and not rely on its callback. Messaging is cleaner and allows to return data to background script more than once.

这篇关于从 Background.js 在页面级别执行代码并返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆