当前位置: 首页 > 面试题库 >

JavaScript使用内容脚本将代码插入页面上下文

拓拔烨赫
2023-03-14
问题内容

我正在学习如何创建Chrome扩展程序。我刚刚开始开发一个捕捉YouTube事件的工具。我想将其与YouTube Flash
Player结合使用(稍后,我将尝试使其与HTML5兼容)。

manifest.json:

{
    "name": "MyExtension",
    "version": "1.0",
    "description": "Gotta catch Youtube events!",
    "permissions": ["tabs", "http://*/*"],
    "content_scripts" : [{
        "matches" : [ "www.youtube.com/*"],
        "js" : ["myScript.js"]
    }]
}

myScript.js:

function state() { console.log("State Changed!"); }
var player = document.getElementById("movie_player");
player.addEventListener("onStateChange", "state");
console.log("Started!");

问题在于控制台为我提供了 “开始!” ,但没有 “状态已更改!” 当我播放/暂停YouTube视频时。

将此代码放入控制台后,它就可以工作了。我究竟做错了什么?


问题答案:

内容脚本在“”isolated world”环境中执行。你必须将state()方法注入页面本身。

如果你想使用chrome.*脚本中的API之一,则必须实现一个特殊的事件处理程序,如以下答案中所述:Chrome扩展程序-检索Gmail的原始消息。

否则,如果你不必使用chrome.*API,则强烈建议你通过添加<script>标签将所有JS代码注入页面中:

  • Method 1: Inject another file
  • Method 2: Inject embedded code
  • Method 2b: Using a function
  • Method 3: Using an inline event
  • Dynamic values in the injected code

方法1:注入另一个文件

当您有很多代码时,这是最简单/最佳的方法。
在扩展名中的文件中包含实际的JS代码,例如script.js。然后,让您的内容脚本如下所示(在此处说明:Google
Chome“应用程序快捷方式”自定义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();

注意:模板文字仅在Chrome41及更高版本中受支持。如果您希望扩展程序在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]) + ')';


 类似资料:
  • 我试图使div内容不流过页脚,我希望内容div随着页面的展开而展开,但是当文本流过页脚时,它会导致页脚在页面上向上跳转 html,body{margin:0;/top,right,bottom,left/padding:0;/top,right,bottom,left/height:100%;}

  • 问题内容: 我遇到了将内容脚本插入页面的问题,该脚本已被history.pushState和ajax调用更改。我找到了类似的主题,但是该解决方案对我不起作用(该解决方案是使用chrome.webNavigation.onHistoryStateUpdated和“ popstate”事件)。 这是我清单的一部分: chrome.webNavigation.onHistoryStateUpdated

  • 本文向大家介绍用JavaScript获取页面文档内容的实现代码,包括了用JavaScript获取页面文档内容的实现代码的使用技巧和注意事项,需要的朋友参考一下 JavaScript的document对象包含了页面的实际内容,所以利用document对象可以获取页面内容,例如页面标题、各个表单值。 以上这篇用JavaScript获取页面文档内容的实现代码就是小编分享给大家的全部内容了,希望能给大家一

  • 问题内容: 我正在尝试让我的Chrome扩展程序在加载新页面时运行该功能,但是在尝试了解如何执行此操作时遇到了麻烦。据我了解,我需要在background.html中执行以下操作: 使用来检查时,页面变更 使用运行的脚本。 这是我的代码: 我还想知道init()函数是否可以访问位于其他JS文件中的其他函数? 问题答案: Chrome扩展程序中的JavaScript代码可以分为以下几类: 扩展代码-

  • 问题内容: 我想一些脚本加载到使用页面上。脚本似乎已加载到DOM中,但从未执行(至少在Firefox和Chrome中)。将脚本插入时,是否可以执行脚本? 样例代码: 问题答案: 您必须使用eval()来执行作为DOM文本插入的任何脚本代码。 MooTools会自动为您执行此操作,而且我敢肯定jQuery也是如此(取决于版本。jQuery 1.6+版本使用)。这样可以节省解析标签和转义内容的麻烦,以

  • 问题内容: 我目前正在开发一个网站,我需要根据用户执行的操作来动态加载页面。 示例:如果用户单击“设置”按钮,则ajax函数将从外部页面加载该代码,并将其放入带有标签“设置”的div中。 这是我用来发出Ajax请求的代码: 这是第一个代码片段将ajax结果放入的位置: 该代码是从此处的函数调用的: 这是ajax函数将放入div 的html : 我想知道是否有一种方法也可以执行ajax函数返回的ja