从由Chrome扩展插入的js访问全局js变量 [英] Access global js variables from js injected by a chrome extension

查看:424
本文介绍了从由Chrome扩展插入的js访问全局js变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个将有侧面面板的扩展程序。这个侧面板将有按钮,将执行基于主机页面状态的操作。



我跟着这个例子来注入侧面板,我可以连接一个onClick监听器按钮。但是,我无法访问全局js变量。在开发人员控制台中,在主机页面的范围内,我可以看到后面的变量(变量名称 - 配置)。但是当我在sidepanel的上下文(popup.html)中出现以下错误 -

VM523:1未捕获的ReferenceError:配置未定义。看起来像popup.html也运行在一个单独的线程中。



如何访问我按钮的onClick处理程序的全局js变量?



我的代码:

manifest.json

< $ p $ {
manifest_version:2,

name:Hello World,
description:测试html注入,
version:1.0,
content_scripts:[{
run_at:document_end,
matches:[
https:// * / *,
http:// * / *

js:[content-script.js]
],
browser_action:{
default_icon:icon.png
},
background:{
scripts :[background.js]
},
permissions:[
activeTab
],
web_accessible_resources:[
popup.html,
popup.js
]
}

background.js

  chrome.browserAction.onClicked.addListener (function(){
chrome.tabs.query({active:true,currentWindow:true},function(tabs){
chrome.tabs.sendMessage(tabs [0] .id,toggle );
})
});

content-script.js

  chrome.runtime.onMessage.addListener(函数(msg,sender){
if(msg ==toggle){
toggle( );
}
})

var iframe = document.createElement('iframe');
iframe.style.background =green;
iframe.style.height =100%;
iframe.style.width =0px;
iframe.style.position =fixed;
iframe.style.top =0px;
iframe.style.right =0px;
iframe.style.zIndex =9000000000000000000;
iframe.frameBorder =none;
iframe.src = chrome.extension.getURL(popup.html)

document.body.appendChild(iframe);

function toggle(){
if(iframe.style.width ==0px){
iframe.style.width =400px;
}
else {
iframe.style.width =0px;
}
}

popup.html

 < head> 
< script src =popup.js> < /脚本>
< / head>
< body>
< h1> Hello World< / h1>

popup.js

  document.addEventListener('DOMContentLoaded',function(){
document.getElementById(toggle)。addEventListener(click,handler);
});

函数处理程序(){
console.log(Hello);
console.log(config);


解决方案



<由于页面JS变量不能直接从扩展中访问,因此需要脚本中插入代码元素,以便它在页面上下文中运行并通过DOM消息将该变量转发到内容脚本中。然后内容脚本可以将消息转发给iframe。




  • 内容脚本:

      runInPage(initConfigExtractor); 

    chrome.runtime.onMessage.addListener((msg,sender,sendResponse)=> {
    switch(msg){
    case'toggle':
    toggle ();
    return;
    case'getConfig':
    window.addEventListener(chrome.runtime.id +'-config',event => {
    sendResponse(event。详细信息);
    },{once:true});
    window.dispatchEvent(new Event(chrome.runtime.id));
    return true;
    }
    )}

    函数initConfigExtractor(extensionId){
    window.addEventListener(extensionId,()=> {
    window.dispatchEvent(new CustomEvent(extensionId +'-config' ,{
    detail:window.config,
    }));
    });


    function runInPage(fn){
    const script = document.createElement('script');
    document.head.appendChild(script).text =
    '((... args)=>('+ fn +')(... args))('+ JSON.stringify (chrome.runtime.id)+')';
    script.remove();
    }


  • iframe脚本:

     函数处理程序(){
    chrome.tabs.getCurrent(tab => {
    chrome.tabs.sendMessage (tab.id,'getConfig',config => {
    console.log(config);
    //用config
    }};
    }};





    $基本上:



    1. iframe脚本获取自己的标签ID并向内容脚本发送消息

    2. 内容脚本向先前插入的页面脚本发送DOM消息
    3. 页面脚本监听该DOM消息并将另一个DOM消息发送回内容脚本
    4. 内容脚本将其发送回iframe脚本中的响应。

    整个事件是异步的,所以在onMessage侦听器中需要 return true 保持消息频道打开。


    I am trying to create an extension that will have a side panel. This side panel will have buttons that will perform actions based on the host page state.

    I followed this example to inject the side panel and I am able to wire up a button onClick listener. However, I am unable to access the global js variable. In developer console, in the scope of the host page I am able to see the variable (name of variable - config) that I am after. but when I which to the context of the sidepanel (popup.html) I get the following error -
    VM523:1 Uncaught ReferenceError: config is not defined. It seems like popup.html also runs in a separate thread.

    How can I access the global js variable for the onClick handler of my button?

    My code:

    manifest.json

    {
        "manifest_version": 2,
    
        "name": "Hello World",
        "description": "This extension to test html injection",
        "version": "1.0",
        "content_scripts": [{
            "run_at": "document_end",
            "matches": [
                "https://*/*",
                "http://*/*"
            ],
            "js": ["content-script.js"]
        }],
        "browser_action": {
            "default_icon": "icon.png"
        },
        "background": {
            "scripts":["background.js"]
        },
        "permissions": [
            "activeTab"
        ],
        "web_accessible_resources": [
            "popup.html",
            "popup.js"
        ]
    }
    

    background.js

    chrome.browserAction.onClicked.addListener(function(){
        chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
            chrome.tabs.sendMessage(tabs[0].id,"toggle");
        })
    });
    

    content-script.js

    chrome.runtime.onMessage.addListener(function(msg, sender){
        if(msg == "toggle"){
            toggle();
        }
    })
    
    var iframe = document.createElement('iframe'); 
    iframe.style.background = "green";
    iframe.style.height = "100%";
    iframe.style.width = "0px";
    iframe.style.position = "fixed";
    iframe.style.top = "0px";
    iframe.style.right = "0px";
    iframe.style.zIndex = "9000000000000000000";
    iframe.frameBorder = "none"; 
    iframe.src = chrome.extension.getURL("popup.html")
    
    document.body.appendChild(iframe);
    
    function toggle(){
        if(iframe.style.width == "0px"){
            iframe.style.width="400px";
        }
        else{
            iframe.style.width="0px";
        }
    }
    

    popup.html

    <head>
    <script src="popup.js"> </script>
    </head>
    <body>
    <h1>Hello World</h1>
    <button name="toggle" id="toggle" >on</button>
    </body>
    

    popup.js

    document.addEventListener('DOMContentLoaded', function() {
      document.getElementById("toggle").addEventListener("click", handler);
    });
    
    function handler() {
      console.log("Hello");
      console.log(config);
    }
    

    解决方案

    Since the page JS variables cannot be directly accessed from an extension, you need to insert code in script element so that it runs in the page context and relays the variable into the content script via DOM messaging. Then the content script can relay the message to the iframe.

    • content script:

      runInPage(initConfigExtractor);
      
      chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
        switch (msg) {
          case 'toggle':
            toggle();
            return;
          case 'getConfig':
            window.addEventListener(chrome.runtime.id + '-config', event => {
              sendResponse(event.detail);
            }, {once: true});
            window.dispatchEvent(new Event(chrome.runtime.id));
            return true;
        }
      })
      
      function initConfigExtractor(extensionId) {
        window.addEventListener(extensionId, () => {
          window.dispatchEvent(new CustomEvent(extensionId + '-config', {
            detail: window.config,
          }));
        });
      }
      
      function runInPage(fn) {
        const script = document.createElement('script');
        document.head.appendChild(script).text =
          '((...args) => (' + fn + ')(...args))(' + JSON.stringify(chrome.runtime.id) + ')';
        script.remove();
      }
      

    • iframe script:

      function handler() {
        chrome.tabs.getCurrent(tab => {
          chrome.tabs.sendMessage(tab.id, 'getConfig', config => {
            console.log(config);
            // do something with config
          });
        });  
      }
      

    So, basically:

    1. the iframe script gets its own tab id and sends a message to the content script
    2. the content script sends a DOM message to a previously inserted page script
    3. the page script listens to that DOM message and sends another DOM message back to the content script
    4. the content script sends it in a response back to the in iframe script.

    The whole thing is asynchronous so return true was needed in the onMessage listener to keep the message channel open.

    这篇关于从由Chrome扩展插入的js访问全局js变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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