内容脚本在“隔离的世界”环境中执行。您必须将state()
方法注入页面本身。
如果您想使用chrome.*
脚本中的API之一,则必须实现特殊的事件处理程序,如以下答案中所述:Chrome扩展程序-检索Gmail的原始消息。
否则,如果您不必使用chrome.*
API,我强烈建议您通过添加<script>
标签将所有JS代码注入页面中:
目录
- 方法1:注入另一个文件
- 方法2:注入嵌入式代码
- 方法2b:使用一个函数
- 方法3:使用一个内联事件
- 注入代码中的动态值
方法1:注入另一个文件
当您有很多代码时,这是最简单/最佳的方法。将实际的JS代码包括在扩展名中的文件中,例如script.js
。然后,让您的内容脚本如下所示(在此处进行说明:Google Chome“ Application Shortcut” Custom Javascript):
var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = chrome.runtime.getURL('script.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
注意:如果使用此方法,则必须将注入的script.js
文件添加到该"web_accessible_resources"
部分(示例)。如果不这样做,Chrome会拒绝加载脚本并在控制台中显示以下错误:
拒绝加载chrome-extension:// [EXTENSIONID] /script.js。必须在web_accessible_resources清单键中列出资源,以便由扩展之外的页面加载。
方法2:注入嵌入式代码
当您想快速运行一小段代码时,此方法很有用。(另请参见:如何使用Chrome扩展程序禁用Facebook热键?)。
var actualCode = `// Code here.
// If you want to use a variable, use $ and curly braces.
// For example, to use a fixed random number:
var someFixedRandomValue = ${ Math.random() };
// NOTE: Do not insert unsafe variables in this way, see below
// at "Dynamic values in the injected code"
`;
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
注意:模板文字仅在Chrome 41及更高版本中受支持。如果您希望扩展程序在Chrome 40-中运行,请使用:
var actualCode = ['/* Code here. Example: */' + 'alert(0);',
'// Beware! This array have to be joined',
'// using a newline. Otherwise, missing semicolons',
'// or single-line comments (//) will mess up your',
'// code ----->'].join('\n');
方法2b:使用一个函数
对于一大段代码,引用字符串是不可行的。除了使用数组,还可以使用函数并对其进行字符串化:
var actualCode = '(' + function() {
// All code is executed in a local scope.
// For example, the following does NOT overwrite the global `alert` method
var alert = null;
// To overwrite a global variable, prefix `window`:
window.alert = null;
} + ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
此方法有效,因为+
字符串和函数的运算符会将所有对象转换为字符串。如果您打算多次使用该代码,则明智的做法是创建一个避免代码重复的函数。一个实现可能看起来像:
function injectScript(func) {
var actualCode = '(' + func + ')();'
...
}
injectScript(function() {
alert("Injected script");
});
注意:由于该函数已序列化,因此原始作用域和所有绑定的属性都将丢失!
var scriptToInject = function() {
console.log(typeof scriptToInject);
};
injectScript(scriptToInject);
// Console output: "undefined"
方法3:使用一个内联事件
有时,您想立即运行一些代码,例如,在<head>
创建元素之前运行一些代码。这可以通过使用插入<script>
标签来完成textContent
(请参见方法2 / 2b)。
一种替代方法,但不建议使用内联事件。不建议这样做,因为如果页面定义了禁止内联脚本的内容安全策略,则内联事件侦听器将被阻止。另一方面,由扩展名注入的内联脚本仍在运行。如果您仍想使用内联事件,则可以这样:
var actualCode = '// Some code example \n' +
'console.log(document.documentElement.outerHTML);';
document.documentElement.setAttribute('onreset', actualCode);
document.documentElement.dispatchEvent(new CustomEvent('reset'));
document.documentElement.removeAttribute('onreset');
注意:此方法假定没有其他全局事件侦听器来处理该reset
事件。如果存在,您还可以选择其他全局事件之一。只需打开JavaScript控制台(F12),输入document.documentElement.on
,然后选择可用事件即可。
注入代码中的动态值
有时,您需要将任意变量传递给注入的函数。例如:
var GREETING = "Hi, I'm ";
var NAME = "Rob";
var scriptToInject = function() {
alert(GREETING + NAME);
};
要注入此代码,您需要将变量作为参数传递给匿名函数。确保正确实施!下面将不工作:
var scriptToInject = function (GREETING, NAME) { ... };
var actualCode = '(' + scriptToInject + ')(' + GREETING + ',' + NAME + ')';
// The previous will work for numbers and booleans, but not strings.
// To see why, have a look at the resulting string:
var actualCode = "(function(GREETING, NAME) {...})(Hi, I'm ,Rob)";
// ^^^^^^^^ ^^^ No string literals!
解决方案是JSON.stringify
在传递参数之前使用。例:
var actualCode = '(' + function(greeting, name) { ...
} + ')(' + JSON.stringify(GREETING) + ',' + JSON.stringify(NAME) + ')';
如果您有很多变量,则值得使用JSON.stringify
一次以提高可读性,如下所示:
...
} + ')(' + JSON.stringify([arg1, arg2, arg3, arg4]) + ')';
player.addEventListener("onStateChange", state);