Chrome扩展程序在已定义的变量上抛出“未定义”的错误

6
我正在尝试使用Chrome扩展程序访问本地变量。在页面脚本中尝试使用console.info(myVar)时,我收到了myVar未定义的错误提示。
然而,当使用Chrome开发者工具并在调试控制台中执行相同的代码片段时,我可以得到myVar的完整内容。
同样的行为也出现在尝试访问window.myVar时,在通过Chrome扩展程序打印时它只是简单的未定义
将一个脚本标签注入到body中,使用以下代码片段通过开发工具和页面脚本,结果是完全相同的行为。
   $("body").append($("<script />", {
      html: "console.info(myVar);"
   }));

在开发工具中执行时,变量被打印出来,但在页面脚本中会出现JavaScript错误。


可能是内容脚本中的页面变量的重复问题。 - Ian
将一个脚本标签注入页面主体(执行console.info(myVar)与上述陈述完全相同。这一定是其他原因。 - patchrail
然而,通过 Chrome 开发工具注入后能够正常打印变量。 - patchrail
内容脚本有一些限制。它们不能:[...] 使用由网页或其他内容脚本定义的变量或函数。http://developer.chrome.com/extensions/content_scripts.html - Oleg
通过直接访问,是的。但是将脚本注入页面主体中应该也可以正常工作。 - patchrail
事实上,一个注入到页面的 script 元素可以访问页面的变量。但它将在页面的上下文中运行,而不是你的扩展中。 - Oleg
2个回答

5
你看到的是预期行为。
内容脚本在一个称为隔离世界的特殊环境中执行。它们可以访问注入页面的DOM,但不能访问页面创建的任何JavaScript变量或函数。对于每个内容脚本来说,它运行的页面上似乎没有其他JavaScript在执行。反过来也是一样:在页面上运行的JavaScript不能调用任何由内容脚本定义的函数或访问任何变量。

http://developer.chrome.com/extensions/content_scripts.html#execution-environment

当你在页面、Chrome开发工具控制台或注入的脚本运行console.info(myVar);时,它在页面上下文中运行,因此可以看到定义的变量。
然而,当从扩展程序代码内部运行相同的代码时,您正在操作完全不同的环境,因此myVar未定义。
您可以尝试使用共享DOM解决此问题。 http://developer.chrome.com/extensions/content_scripts.html#host-page-communication 编辑:
除非有人纠正我,否则下面的console.info(myVar);代码被注入到script元素中,同时仍在扩展程序的上下文中执行。
$("<script />", {
    html: "console.info(myVar);" // myVar points to extension's myVar, not page's
});

一个简单的测试可以通过记录chrome.extension对象或在contentscript中声明myVar来运行- chrome.extension将可用,并且myVar将被记录为contentscript中定义的内容。

建议使用外部脚本(这也更好地实现了模块化),将其添加到web_accessible_resources并创建一个带有指向该外部脚本的src属性的script元素。

下面是示例扩展代码,在启用扩展的情况下加载test.html页面时会弹出“test”。

manifest.json

{
    "name": "Test",
    "version": "0.1.0",
    "manifest_version": 2,
    "description": "Just a test.",
    "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["contentscript.js"]
    }],
    "web_accessible_resources": [
        "myscript.js"
    ]
}

test.html(访问的页面)

<!DOCTYPE html>
<html>
<head>
    <script>
        window.test = 'test';
    </script>
</head>
<body>
</body>
</html>

contentscript.js

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = chrome.extension.getURL('myscript.js');
document.getElementsByTagName('head')[0].appendChild(script);

myscript.js(这是在页面上下文中运行的外部脚本)

alert(window.test);

即使在 pages 上下文中执行注入的脚本标签,也无法解释为什么该标签看不到 pages 变量 - 请参见我上面的编辑。但是,通过 dev 工具注入则可以正常工作。 - patchrail
是的。此外,该页面还附带了jQuery。 - patchrail
你确定这是同一个错误吗?不是诸如“未捕获的ReferenceError: $未定义”之类的错误吗? - Oleg
100%确定。此外,发现即使通过页面脚本和开发工具注入的脚本标记打印时,窗口对象也存在某些属性上的差异。我已经没有更多的想法了。 - patchrail
在我的端上,我完全没有问题注入脚本并记录虚拟的 myVar 变量(尽管我没有使用 jQuery)。也许你是在 myVar 创建之前运行你的扩展代码? - Oleg
让我们在聊天室继续这个讨论。点击此处进入 - patchrail

2

Oleg和我在聊天室中找到了问题的源头。

我尝试使用以下代码片段注入脚本:

   $("body").append($("<script />", {
      html: "console.info(myVar);"
   }));

正如Oleg在他的回答中所写的那样,看起来console.info部分在到达页面主体之前就被执行了,导致扩展上下文出现在这里。然而,非jQuery版本运行良好:

var g = document.createElement('script'); 
var s = document.getElementsByTagName('script')[0]; 
g.text = "console.info(myVar);" 
s.parentNode.insertBefore(g, s);

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