为什么需要chrome.tabs.executeScript()来更改当前的网站DOM?如何使用jQuery来实现相同的效果?

为什么需要chrome.tabs.executeScript()来更改当前的网站DOM?如何使用jQuery来实现相同的效果?,jquery,google-chrome-extension,Jquery,Google Chrome Extension,更新: 我最近收到了太多的负面评论,这是一个非常古老的问题(2.5年)。我甚至不再使用jquery了。所以请让它休息一下 我以前已经做过一些chrome扩展,但这是我第一次需要更改用户当前查看的网站上的某些内容,以响应扩展弹出窗口中的按钮单击 正如我意识到的,仅仅执行一些jQuery行没有任何效果。我在google开发者页面示例扩展名:chrome.tabs.executeScript()上找到了一个有效的方法,但我不知道为什么需要它 一定有一些我不知道的基本概念。谁能给我解释一下吗?我也可以

更新: 我最近收到了太多的负面评论,这是一个非常古老的问题(2.5年)。我甚至不再使用jquery了。所以请让它休息一下


我以前已经做过一些chrome扩展,但这是我第一次需要更改用户当前查看的网站上的某些内容,以响应扩展弹出窗口中的按钮单击

正如我意识到的,仅仅执行一些jQuery行没有任何效果。我在google开发者页面示例扩展名:
chrome.tabs.executeScript()
上找到了一个有效的方法,但我不知道为什么需要它

一定有一些我不知道的基本概念。谁能给我解释一下吗?我也可以执行jQuery(已加载)吗

完整示例:

$('#change_button').on('click', function() {

  //this doesen't work
  $("body").css({backgroundColor: 'blue'});

  //but this line does
  chrome.tabs.executeScript(null, {code:"document.body.style.backgroundColor='red'"});

});
实际上,我非常需要jQuery在DOM中进行更多的更改并对其作出响应,即:

if( $(".list,.list-header-name").hasClass("tch"))
{
  $(".list,.list-header-name").addClass("tch");
}

在Chrome扩展中运行的Javascript在后台页面或某个弹出页面中运行。它不是运行扩展时浏览器中的页面。这就是为什么需要在特定选项卡内执行脚本

为了更好地可视化,右键单击扩展的按钮,然后选择Inspect Popup。与背景页相同,请转到chrome://extensions 到您的(大概)未打包的扩展,然后单击背景页面,您就有了开发人员工具来查看正在发生的事情

为了将一些资源打包到chrome扩展中,以便以后可以从网页直接访问这些资源,您可以使用。基本上,您可以声明希望网页可以访问的文件,然后使用“chrome extension://[PACKAGE ID]/[PATH]”格式的URL将其加载或注入。为了使用此机制并使打包的jQuery库可用于网页,我们添加了:

"web_accessible_resources": [
    "jquery-2.2.2.min.js"
]
在manifest.json中

要从扩展访问网页,您需要为其添加:

此函数将jQuery从扩展加载到网页,然后在安装时执行回调。从那时起,可以使用相同的
chrome.tabs.executeScript(tab.id,{code/file:
)在远程页面上使用jQuery运行脚本

由于它使用带有file选项的executeScript方法,因此不需要脚本的web\u accessible\u资源声明

从下面的一条好评论中,我了解到了。 executeScript在“孤立的世界”中运行,因此它没有 访问全局变量和执行的任何内容都不会创建 网页可以访问的东西。所以整个过程很复杂 上面的功能是多余的。如果你不想,你仍然可以使用这个系统 与页面上的代码交互,但仅与其DOM交互,而不必担心 代码有冲突吗

但是扩展确实可以访问选项卡的文档。下面是一个函数,它使用前面介绍的web\u accessible\u resources机制在网页中创建脚本标记,然后加载打包在扩展中的jQuery库:

// executeScript's a function rather than a string
function remex(tabId, func,callback) {
    chrome.tabs.executeScript(tabId,{ code: '('+func.toString()+')()' },callback);
}

function initJqueryOnWebPage(tab, callback) {
    // the function to be executed on the loaded web page
    function f() {
        // return if jQuery is already loaded as ex$
        if (window.ex$) return;
        // create a script element to load jQuery
        var script=document.createElement('script');
        // create a second script tag after loading jQuery, to avoid conflicts
        script.onload=function() {
            var noc=document.createElement('script');
            // this should display in the web page's console
            noc.innerHTML='window.ex$=jQuery.noConflict(true); console.log(\'jQuery is available as \',window.ex$);';
            document.body.appendChild(noc);
        };
        // use extension.getURL to get at the packed script
        script.src=chrome.extension.getURL('jquery-2.2.2.min.js');
        document.body.appendChild(script);
    };
    // execute the content of the function f
    remex(tab.id,f,function() { 
       console.log('jQuery injected'); // this should log in the background/popup page console
       if (typeof(callback)=='function') callback();
    });
}
向executeScripts发送脚本很麻烦,这就是我在上面使用remex函数的原因。请注意,remex在“孤立世界”环境中执行函数,与在文档中附加脚本标记时由选项卡执行的代码之间存在差异。不过,在这两种情况下,实际执行的都是字符串s、 因此,请注意不要试图跨上下文携带对象或函数

两个连续的remex调用将在各自的上下文中执行,因此即使在一个上下文中加载jQuery,也无法在下一个上下文中使用它。不过,可以使用与initJqueryOnWebPage相同的系统,这意味着将代码添加到页面上的脚本中。下面是一些代码,请像
remex
一样使用它:

function windowContextRemex(tabId,func,callback) {
    var code=JSON.stringify(func.toString());
    var code='var script = document.createElement("script");'+
        'script.innerHTML = "('+code.substr(1,code.length-2)+')();";'+
        'document.body.appendChild(script)';
    chrome.tabs.executeScript(tabId, {
        code : code
    }, function () {
        if (callback)
            return callback.apply(this, arguments);
    });
}
因此,我在这里演示:

  • 在仅能访问DOM的隔离上下文中执行代码 在选项卡中打开的页面的
  • 在与上面相同的上下文中执行打包脚本
  • 注入在页面上下文中运行的脚本
缺少什么:

  • 一种链接代码的好方法,这样您就不必创建 手动脚本元素
  • 通过insertCSS加载CSS文件(类似于带有 文件选项,但直接在页面中加载

弹出页面存在于扩展上下文中,而当前网页中的DOM是另一个上下文,它们是不同的进程,因此需要一些通信方式,
选项卡。executeScript
是一种以编程方式将代码插入页面的方法

如果您严重依赖jQuery,而不是直接插入代码,那么可以先插入文件,然后使用jQuery方法

chrome.tabs.executeScript(null, {file: "jquery.js"}, function() {
    chrome.tabs.executeScript(null, {code:"$("body").css({backgroundColor: 'blue'})");

除了编程注入,您还可以通过在
manifest.json
中指定
matches
字段来注入内容脚本。这样,当用户单击弹出页面中的按钮时,您可以使用来在扩展过程和内容脚本之间进行通信,然后使用内容脚本来操作当前页面。

您缺少的是弹出窗口的javascript只影响弹出窗口的DOM。要影响选项卡的DOM,您需要使用内容脚本(从清单或通过注入它)

假设您将其作为popup.html:


弹出式html
正文{填充:3em;}
按钮{宽度:10em;边距:1ex;}

给弹出窗口涂上颜色
给网页上色
注入jQuery

这是popup.js:

$('onlypoup')。单击(函数(){
$(“body”).css('backgroundColor','blue');
});
$(“#影响网页”)。单击(函数(){
chrome.tabs.executeScript(null,{code:“document.body.style.backgroundColor='red'”});
});
$(“#jqWebpage”)。单击(函数(){
executeScript(null,{file:“jquery.min.js”},callba
function windowContextRemex(tabId,func,callback) {
    var code=JSON.stringify(func.toString());
    var code='var script = document.createElement("script");'+
        'script.innerHTML = "('+code.substr(1,code.length-2)+')();";'+
        'document.body.appendChild(script)';
    chrome.tabs.executeScript(tabId, {
        code : code
    }, function () {
        if (callback)
            return callback.apply(this, arguments);
    });
}
chrome.tabs.executeScript(null, {file: "jquery.js"}, function() {
    chrome.tabs.executeScript(null, {code:"$("body").css({backgroundColor: 'blue'})");