Chrome扩展程序 - 从网页检索全局变量

时间:2012-03-07 13:01:49

标签: javascript html dom google-chrome-extension

我正在开发Chrome扩展程序。我希望解析“原始”Gmail邮件(当前查看的邮件)的内容。

我尝试使用jQuery.load(),如下所示

$(windows).load(function() { alert(GLOBALS); });

并将其放在内容脚本中,但它也不起作用。我正在使用Chrome的开发人员工具,它会在调用alert(GLOBALS);

时返回以下错误
  

未捕获的ReferenceError:未定义GLOBALS

虽然,在使用开发人员工具的控制台时,键入控制台GLOBALS它会返回一个数组。

如何从内容脚本访问GLOBALS?

5 个答案:

答案 0 :(得分:86)

Content scripts在孤立的环境中运行。要访问(页面的window)的任何全局属性,您必须注入新的<script>元素,或使用事件侦听器来传递数据。

有关在页面上下文中注入<script>元素的示例,请参阅this answer

实施例

contentscript.js (清单中的"run_at": "document_end"):

var s = document.createElement('script');
s.src = chrome.extension.getURL('script.js');
(document.head||document.documentElement).appendChild(s);
s.onload = function() {
    s.remove();
};

// Event listener
document.addEventListener('RW759_connectExtension', function(e) {
    // e.detail contains the transferred data (can be anything, ranging
    // from JavaScript objects to strings).
    // Do something, for example:
    alert(e.detail);
});

script.js - 位于扩展程序目录中,会将其注入页面本身:

setTimeout(function() {
    /* Example: Send data from the page to your Chrome extension */
    document.dispatchEvent(new CustomEvent('RW759_connectExtension', {
        detail: GLOBALS // Some variable from Gmail.
    }));
}, 0);

由于此文件是通过chrome-extension:DOM从DOM中加载的,因此必须将“script.js”添加到清单文件的web_accessible_resources部分。否则Chrome会拒绝加载脚本文件。

您应该在网页中尽可能少地运行逻辑,并在内容脚本中处理大部分逻辑。这有多种原因。首先,页面中注入的任何脚本都在与网页相同的上下文中运行,因此网页可以(故意或无意)修改JavaScript / DOM方法,使扩展程序停止工作。其次,内容脚本可以访问额外的功能,例如chrome。* API和跨域网络请求的有限子集(前提是扩展已声明这些功能的权限)。

答案 1 :(得分:20)

用于在chrome扩展content_script和页面上的javascript之间进行通信的更现代的解决方案是使用html5 postMessage API。发送到“窗口”的任何消息都可以从网页上的javascript和扩展名的content_script中看到。

扩展名的content_script.js:

window.addEventListener('message', function(event) {
    console.log('content_script.js got message:', event);
    // check event.type and event.data
});

setTimeout(function () {
    console.log('cs sending message');
    window.postMessage({ type: 'content_script_type',
                         text: 'Hello from content_script.js!'},
                       '*' /* targetOrigin: any */ );
}, 1000);

网页上运行的javascript:

window.addEventListener('message', function(event) {
    console.log('page javascript got message:', event);
});

setTimeout(function() {
    console.log('page javascript sending message');
    window.postMessage({ type: 'page_js_type',
                         text: "Hello from the page's javascript!"},
                       '*' /* targetOrigin: any */);
}, 2000);

另见http://developer.chrome.com/extensions/content_scripts.html#host-page-communication

答案 2 :(得分:3)

有一个新的网页API可以安全地进行通信,而且没有任何副作用(window.postMessage可以有其他监听器!)到内容脚本。

“从网页中,使用runtime.sendMessage或runtime.connect API将消息发送到特定应用或扩展”

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
    handleError(url);
});

“从您的应用或扩展程序中,您可以通过runtime.onMessageExternal或runtime.onConnectExternal API收听来自网页的消息,类似于跨扩展消息传递。只有网页才能启动连接。[...] “

(来自http://developer.chrome.com/extensions/messaging.html) 这仍然只在chrome的开发频道中提供,但似乎它将在下一个版本左右。

不要问我这是如何工作的,这似乎非常令人困惑。如何在网页上定义chrome.runtime?如果脚本由于某种原因已经定义了该变量怎么办?我也找不到铬虫报告,看看这个功能发展的历史。

答案 3 :(得分:0)

根据您的扩​​展程序的可访问html页面,我的方法略有不同。

将您的页面添加到清单:

"web_accessible_resources": ["variables.html"]

创建您的页面(此处为variables.html)并提取内容的数据(即window.contentVar):

<script type="text/javascript">
  $("#my-var-name").text(window["contentVar"]);
</script>
<div id="my-var-name" style="display: none;"></div>

从您的扩展程序访问JavaScript:

var myVarName = $("#my-var-name").text();

答案 4 :(得分:0)

添加到您的内容脚本中:

function executeOnPageSpace(code){

  // create a script tag
  var script = document.createElement('script')
  script.id = 'tmpScript'
  // place the code inside the script. later replace it with execution result.
  script.textContent = 
  'document.getElementById("tmpScript").textContent = JSON.stringify(' + code + ')'
  // attach the script to page
  document.documentElement.appendChild(script)
  // collect execution results
  let result = document.getElementById("tmpScript").textContent
  // remove script from page
  script.remove()
  return JSON.parse(result)

}

现在您可以这样做:

let window = executeOnPageSpace('window')

甚至是这样:

executeOnPageSpace('window.location.href = "http://stackoverflow.com"')

注意:我尚未针对长时间运行的代码进行过测试。