为什么需要chrome.tabs.executeScript()更改当前网站的DOM,以及如何使用jQuery实现相同的效果? [英] Why is chrome.tabs.executeScript() necessary to change the current website DOM and how can I use jQuery to achieve the same effect?

查看:135
本文介绍了为什么需要chrome.tabs.executeScript()更改当前网站的DOM,以及如何使用jQuery实现相同的效果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前已经制作了一些Chrome扩展程序,但这是我第一次需要更改网站上用户当前正在查看的内容,以响应放置在扩展程序弹出窗口中的按钮点击。



当我意识到只是执行一些jQuery线没有效果。我在google开发者页面示例扩展中找到了一个方法: chrome.tabs.executeScript()但我不知道为什么这是必要的。

必须有一些基本的概念我不知道。任何人都可以向我解释吗?我可以执行jQuery(也被加载)吗?



完整示例:

 <$ ('click',function(){

//这个doesen't工作
$(body)。css(code $('#change_button' {backgroundColor:'blue'});

//但是这行代码是
chrome.tabs.executeScript(null,{code:document.body.style.backgroundColor ='red' });

});

实际上,我需要jQuery对DOM进行一些更改并对它们做出响应, ($。list,.list-header-name)。hasClass(tch))
($。

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


解决方案

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



为了更好地形象化,请右键单击扩展的按钮,然后选择检查弹出式窗口。对于背景页面,请使用chrome://扩展到您的(大概)解压后的扩展名,然后单击背景页面,然后使用开发人员工具查看正在发生的事情。



为了在你的chrome扩展中打包一些资源,以便稍后通过网页直接访问它们,你可以使用 Web无障碍资源。基本上,你声明你想访问的网页文件,然后你可以加载它们或使用形式为chrome-extension:// [PACKAGE ID] / [PATH]的URL注入它们。为了使用这种机制并使打包的jQuery库可用于网页,我们添加:

 web_accessible_resources:[
jquery-2.2.2.min.js
]

.json。



为了从扩展中访问网页,您需要添加权限

 permissions:[
tabs,
[...]
< all_urls>,
file:// * / *,
http:// * / *,
https:// * / *
],

也在manifest.json中。 < all_urls> 是一个特殊的关键字,不是我在那里添加的,它是任何类型的URL的占位符,不管架构如何。如果您只需要http和https URL,只需使用最后两个。



这是一个在特定标签的页面中加载jQuery的函数,它的名称为ex $,以便它不与其他库或jQuery版本冲突。

){
//查看是否已经注入
chrome.tabs.executeScript(tab.id,{code:'!! window.ex $'},function(installed){
//然后返回
if(installed [0])return;
//从扩展中加载脚本(url为chrome.extension.getUrl('jquery-2.2.2.min.js'))
chrome.tabs.executeScript(tab.id,{file:'jquery-2.2.2.min.js'},function(){
//确保我们没有冲突
//并返回true回调
chrome.tabs.executeScript(tab.id,{code:'window.ex $ = jQuery.noConflict(true); true'},callback);
});
});
}

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



因为它将executeScript方法与file选项一起使用,所以它不需要脚本的web_accessible_resources声明


从下面的好评中,我了解了执行环境
executeScript在孤立的世界中运行,因此它没有
访问全局变量的权限,任何执行的操作都不会创建
可以通过因此,上面的整个复杂的
函数是过度的,如果你不想让
与页面上的代码交互,但是只使用它的DOM,并且不关心$ b,你仍然可以使用这个系统$ b与任何代码冲突


但是e xtension确实可以访问该选项卡的文档。这是一个函数,首先使用web_accessible_resources机制在网页中创建脚本标记,然后加载打包在扩展中的jQuery库: p> // executeScript是一个函数而不是字符串
函数remex(tabId,func,callback){
chrome.tabs.executeScript(tabId,{code:'('+ func.toString()+')()'},callback);


函数initJqueryOnWebPage(tab,callback){
//在加载的网页上执行的函数
函数f(){
//如果jQuery已经被加载为ex $
,则返回if(window.ex $)return;
//创建一个脚本元素来加载jQuery
var script = document.createElement('script');
//在加载jQuery之后创建第二个脚本标记,以避免冲突
script.onload = function(){
var noc = document.createElement('script');
//这应该显示在网页的控制台中
noc.innerHTML ='window.ex $ = jQuery.noConflict(true); console.log(\'jQuery可用作\',window.ex $);';
document.body.appendChild(noc);
};
//使用extension.getURL获取打包脚本
script.src = chrome.extension.getURL('jquery-2.2.2.min.js');
document.body.appendChild(script);
};
//执行函数f
的内容remex(tab.id,f,function(){
console.log('jQuery inject'); //这会登录背景/弹出页面控制台
if(typeof(callback)=='function')callback();
});
}

将脚本发送到executeScripts很麻烦,这就是为什么我使用remex功能如上。请注意,remex在隔离的世界环境中执行一个函数,而在脚本标签附加到文档时由选项卡执行的代码存在差异。但是,在这两种情况下,实际执行的是字符串,因此请小心不要尝试在上下文中携带对象或函数。

连续的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 );
});

$ / code>

所以我在这里证明了:


  • 在隔离的上下文中执行代码,该代码只能访问在选项卡中打开的页面的DOM

  • 执行打包的脚本在与上述相同的上下文中
  • 注入在页面上下文中运行的脚本



缺少的是什么:




  • 链接代码的一种很好的方式,以便您不必手动创建
    脚本元素

  • 通过insertCSS加载CSS文件(类似于带有
    文件选项的executeScript,但直接加载到页面中)

I have already made some chrome extensions before but this is the first time I need to change something on the website the user is current looking at to respond to button clicks placed in the extension popup.

As I realized just executing some jQuery lines have no effect. What works is a method I found on google developer page sample extension: chrome.tabs.executeScript() but I have no clue why it's necessary.

There must be some basic concept I'm not aware of. Could anyone explain it to me? An can I execute jQuery (which is loaded) too?

Full example:

$('#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'"});

});

Actually I need jQuery badly to make some more changes in the DOM and respond to them i.e:

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

解决方案

The Javascript you are running in your Chrome extension is run either in the background page or some popup page. It is NOT the page in your browser where you were when running the extension. That is why you need to executeScript inside a specific tab.

To visualize this better, right click on the button of your extension, and select Inspect Popup. The same for a background page, go to chrome://extensions to your (presumably) unpacked extension and click on background page, and you have developer tools to see what is going on.

In order to package some resources in your chrome extension so they can be used by direct access from web pages later on, you can use Web Accessible Resources. Basically you declare the files that you want accessible by the web pages, then you can load them in or inject them using a URL of the form "chrome-extension://[PACKAGE ID]/[PATH]". In order to use this mechanism and make the packaged jQuery library available to web pages, we add:

"web_accessible_resources": [
    "jquery-2.2.2.min.js"
]

in manifest.json.

In order to have access to web pages from the extension, you need to add permissions for it:

"permissions" : [
    "tabs",
    [...]
    "<all_urls>",
    "file://*/*",
    "http://*/*",
    "https://*/*"
],

also in manifest.json. <all_urls> is a special keyword not something I added there and it is a placeholder for any type of URL, regardless of schema. If you want only http and https URLs, just use the last two only.

Here is a function that loads jQuery in the page of a certain tab, assigning it the name ex$ so that it doesn't conflict with other libraries or versions of jQuery.

function initJqueryOnWebPage(tab, callback) {
    // see if already injected
    chrome.tabs.executeScript(tab.id,{ code: '!!window.ex$'},function(installed) {
        // then return
        if (installed[0]) return;
        // load script from extension (the url is chrome.extension.getUrl('jquery-2.2.2.min.js') )
        chrome.tabs.executeScript(tab.id,{ file: 'jquery-2.2.2.min.js' },function() {
            // make sure we get no conflicts
            // and return true to the callback
            chrome.tabs.executeScript(tab.id,{ code: 'window.ex$=jQuery.noConflict(true);true'},callback);
        });
    });
}

This function is loading jQuery from the extension to the web page, then executes a callback when it's installed. From then one can use the same chrome.tabs.executeScript(tab.id,{ code/file: to run scripts using jQuery on the remote page.

Since it uses the executeScript method with the file option, it doesn't need the web_accessible_resources declaration for the script

From a nice comment below, I learned about execution environment. executeScript runs in an "isolated world" so that it doesn't have access to global variables and whatever gets executed doesn't create something that can be accessed by the web page. So the entire complicated function above is overkill. You can still use this system if you do not want to interact with code on the page, but just with its DOM, and be unconcerned with any conflicts in code

But the extension does have access to the document of the tab. Here is a function that uses the web_accessible_resources mechanism described at first to create a script tag in the web page that then loads the jQuery library that is packaged in the extension:

// 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();
    });
}

It is cumbersome to send scripts to executeScripts, that is why I used the remex function above. Note that there is a difference between remex, which executes a function in the 'isolated world' environment and the code executed by the tab when a script tag is appended to the document. In both cases, though, what actually gets executed is strings, so be careful not to try to carry objects or functions across contexts.

Two consecutive remex calls will be executed in their own context, so even if you load jQuery in one, you won't have it available in the next. One can use the same system as in initJqueryOnWebPage, though, meaning adding the code to a script on the page. Here is a bit of code, use it just like 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);
    });
}

So here I have demonstrated:

  • executing code in an isolated context that has only access to the DOM of a page opened in a tab
  • executing packaged scripts in the same context as above
  • injecting scripts that run in the context of the page

What is missing:

  • a nice way of chaining code so that you don't have to create the script element manually
  • loading CSS files through insertCSS (akin to executeScript with a file option, but that load directly in the page

这篇关于为什么需要chrome.tabs.executeScript()更改当前网站的DOM,以及如何使用jQuery实现相同的效果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆