gpt4 book ai didi

google-chrome-extension - 从 chrome 扩展注入(inject)的 js 访问全局 js 变量

转载 作者:行者123 更新时间:2023-12-04 17:07:12 25 4
gpt4 key购买 nike

我正在尝试创建一个具有侧面板的扩展。此侧面板将具有将根据主机页面状态执行操作的按钮。

我关注了this example注入(inject)侧面板,我可以连接一个按钮 onClick 监听器。但是,我无法访问全局 js 变量。在开发人员控制台中,在主机页面的范围内,我能够看到我所追求的变量(变量名称 - 配置)。但是当我进入侧面板(popup.html)的上下文时,我收到以下错误 -
VM523:1 未捕获的 ReferenceError:未定义配置。似乎 popup.html 也运行在一个单独的线程中。

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

我的代码:

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"
]
}

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

内容脚本.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);
}

最佳答案

由于内容脚本在“孤立世界”中运行,因此无法从扩展直接访问页面的 JS 变量,您需要 run code in page's main world .
警告! DOM 元素无法提取为元素,因此只需发送它的 innerHTML或其他属性。只能提取与 JSON 兼容的数据类型(字符串、数字、 bool 值、null 和这些类型的数组/对象),没有循环引用。
1. 现代 Chrome 95 或更新版本中的 ManifestV3
这是扩展弹出/后台脚本中的完整代码:

async function getPageVar(name, tabId) {
const [{result}] = await chrome.scripting.executeScript({
func: name => window[name],
args: [name],
target: {
tabId: tabId ??
(await chrome.tabs.query({active: true, currentWindow: true}))[0].id
},
world: 'MAIN',
});
return result;
}
用法:
(async () => {
const v = await getPageVar('foo');
console.log(v);
})();
另见 how to open correct devtools console .
2. 旧版 Chrome 中的 ManifestV3 和 ManifestV2
我们将提取变量并通过 DOM 消息将其发送到内容脚本中。然后内容脚本可以将消息中继到 iframe 或弹出/背景页面中的扩展脚本。
  • list V3 对于 Chrome 94 或更早版本需要两个单独的文件
    内容脚本:
    const evtToPage = chrome.runtime.id;
    const evtFromPage = chrome.runtime.id + '-response';

    chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
    if (msg === 'getConfig') {
    // DOM messaging is synchronous so we don't need `return true` in onMessage
    addEventListener(evtFromPage, e => {
    sendResponse(JSON.parse(e.detail));
    }, {once: true});
    dispatchEvent(new Event(evtToPage));
    }
    });

    // Run the script in page context and pass event names
    const script = document.createElement('script');
    script.src = chrome.runtime.getURL('page-context.js');
    script.dataset.args = JSON.stringify({evtToPage, evtFromPage});
    document.documentElement.appendChild(script);
    page-context.js 应该暴露在 manifest.json 的 web_accessible_resources 中, example .
    // This script runs in page context and registers a listener.
    // Note that the page may override/hook things like addEventListener...
    (() => {
    const el = document.currentScript;
    const {evtToPage, evtFromPage} = JSON.parse(el.dataset.args);
    el.remove();
    addEventListener(evtToPage, () => {
    dispatchEvent(new CustomEvent(evtFromPage, {
    // stringifying strips nontranferable things like functions or DOM elements
    detail: JSON.stringify(window.config),
    }));
    });
    })();
  • list V2 内容脚本:
    const evtToPage = chrome.runtime.id;
    const evtFromPage = chrome.runtime.id + '-response';

    // this creates a script element with the function's code and passes event names
    const script = document.createElement('script');
    script.textContent = `(${inPageContext})("${evtToPage}", "${evtFromPage}")`;
    document.documentElement.appendChild(script);
    script.remove();

    // this function runs in page context and registers a listener
    function inPageContext(listenTo, respondWith) {
    addEventListener(listenTo, () => {
    dispatchEvent(new CustomEvent(respondWith, {
    detail: window.config,
    }));
    });
    }

    chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
    if (msg === 'getConfig') {
    // DOM messaging is synchronous so we don't need `return true` in onMessage
    addEventListener(evtFromPage, e => sendResponse(e.detail), {once: true});
    dispatchEvent(new Event(evtToPage));
    }
    });
  • 同一选项卡中扩展 iframe 脚本的用法示例:
    function handler() {
    chrome.tabs.getCurrent(tab => {
    chrome.tabs.sendMessage(tab.id, 'getConfig', config => {
    console.log(config);
    // do something with config
    });
    });
    }
  • 弹出脚本或后台脚本的使用示例:
    function handler() {
    chrome.tabs.query({active: true, currentWindow: true}, tabs => {
    chrome.tabs.sendMessage(tabs[0].id, 'getConfig', config => {
    console.log(config);
    // do something with config
    });
    });
    }

  • 所以,基本上:
  • iframe 脚本获取其自己的选项卡 ID(或弹出/背景脚本获取事件选项卡 ID)并向内容脚本发送消息
  • 内容脚本向先前插入的页面脚本发送 DOM 消息
  • 页面脚本监听该 DOM 消息并将另一条 DOM 消息发送回内容脚本
  • 内容脚本将其作为响应发送回扩展脚本。
  • 关于google-chrome-extension - 从 chrome 扩展注入(inject)的 js 访问全局 js 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46869780/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com