javascript - 在新选项卡/窗口中传递数据或修改扩展 html
问题描述
我正在尝试将 DOM 附加到从popup.js
. 假设我在 chrome 扩展文件中存在一个temp.html
文件,popup.js
名为chrome.tabs.create
无论如何我可以这样做popup.js
吗?
Extension files:
1-manifest.json
2-functions
functions.js
domToTables.js
3-libs
jquery-3.3.1.min.js
bootstrap-4.2.1-dist
4-myTables
stylesheet.css
*temp.html* \\this file
5-popup
stylesheet.css
index.html
popup.js
6-background.js
7-content.js
解决方案
尽管您可以使用 chrome.extension.getViews 直接访问在新选项卡/窗口中打开的您自己的扩展页面的 DOM(如果使用 window.open 则更简单),但这是 UI 原始时代的方法,所以它如果您打开的页面使用演示框架,则无法使用。此外,当从弹出窗口中使用时,您必须先在后台打开选项卡(active:false
在 chrome.tabs.create 的参数中),否则弹出窗口将自动关闭,因此不会运行进一步的代码,不幸的是,这仍然不可靠,因为另一个扩展可能会强制激活选项卡。
可靠/正确的方法是将数据传递给另一个页面,并让它处理其脚本中的数据,该脚本通过标准 html 加载到该页面中<script src="other-page.js"></script>
。
1. MV2:HTML5 localStorage + 同步访问
如果您需要在第一个绘制帧之前在其他页面内加载期间访问数据,例如选择浅色/深色主题,请使用此选项。
缺点:大量数据可能会显着降低预算设备的速度,并且您必须对非字符串类型(例如对象或数组)进行 JSON 化处理。
popup.js:
localStorage.sharedData = JSON.stringify({foo: 123, bar: [1, 2, 3], theme: 'dark'});
chrome.tabs.create({url: 'other-page.html'});
其他页面.js:
let sharedData;
try {
sharedData = JSON.parse(localStorage.sharedData);
if (sharedData.theme === 'dark') {
document.documentElement.style = 'background: #000; color: #aaa;';
}
} catch (e) {}
delete localStorage.sharedData;
2. MV2/MV3:URL参数+同步访问
如果您需要在第一个绘制帧之前在其他页面内加载期间访问数据,例如选择浅色/深色主题,请使用此选项。
缺点:地址栏中的 url 很长,您必须对非字符串类型(例如对象或数组)进行 JSON 化处理。
popup.js:
chrome.tabs.create({
url: 'other-page.html?data=' + encodeURIComponent(JSON.stringify({foo: [1, 2, 3]})),
});
其他页面.js:
let sharedData;
try {
sharedData = JSON.parse(new URLSearchParams(location.search).get('data'));
} catch (e) {}
// simplify the displayed URL in the address bar
history.replace({}, document.title, location.origin + location.pathname);
3. MV2:后台脚本的全局变量+同步访问
如果您需要在第一个绘制帧之前在其他页面内加载期间访问数据,例如选择浅色/深色主题,请使用此选项。
缺点1:需要背景页面。
缺点 2:需要使用 JSON.parse(JSON.stringify(data)) 或自定义 deepClone 对对象进行深度克隆,该对象适用于跨窗口上下文,因为没有一个流行的 deepClone 实现可以这样做 AFAIK:特别应该使用window
对象构造函数的 target 引用。
清单.json:
"background": {
"scripts": ["bg.js"],
"persistent": false
}
popup.js:
// ensure the non-persistent background page is loaded
chrome.runtime.getBackgroundPage(bg => {
// using JSON'ification to avoid dead cross-window references.
bg.sharedData = JSON.stringify({foo: 123, bar: [1, 2, 3], theme: 'dark'});
chrome.tabs.create({url: 'other-page.html'});
});
其他页面.js:
// if this tab was reloaded the background page may be unloaded and the variable is lost
// but we were saving a copy in HTML5 sessionStorage!
let sharedData = sessionStorage.sharedData;
if (!sharedData) {
const bg = chrome.extension.getBackgroundPage();
sharedData = bg && bg.sharedData;
if (sharedData) {
sessionStorage.sharedData = sharedData;
}
}
// using JSON'ification to avoid dead cross-window references.
try {
sharedData = JSON.parse(sharedData);
} catch (e) {}
4. MV2/MV3:两跳后台脚本中继消息
如果您需要在后台页面中执行一系列操作,而打开选项卡只是第一步,请使用此选项。例如我们需要在第二步中传递数据。
需要后台页面,因为当在显示弹出窗口的同一窗口中打开活动选项卡时,弹出窗口将关闭并且其脚本将不再运行。有人可能认为创建一个选项卡active: false
可以解决问题,但只有在用户决定安装另一个覆盖选项卡打开行为的扩展之前。您会认为您可以打开一个新窗口,但不能保证其他扩展不会将新窗口的选项卡重新附加到现有窗口中,从而关闭您的弹出窗口。
缺点 1:在 Chrome 中,数据在内部是 JSON 化的,因此它会破坏所有非标准类型,例如 WeakMap、TypedArray、Blob 等。在 Firefox 中,它们似乎正在使用结构化克隆,因此可以共享更多类型。
缺点2:我们发送了两次相同的数据消息。
注意:我使用的是Mozilla 的 WebExtension polyfill。
清单.json:
"background": {
"scripts": [
"browser-polyfill.min.js",
"bg.js"
],
"persistent": false
}
popup.js:
chrome.runtime.sendMessage({
action: 'openTab',
url: '/other-page.html',
data: {foo: 123, bar: [1, 2, 3], theme: 'dark'},
});
bg.js:
function onTabLoaded(tabId) {
return new Promise(resolve => {
browser.tabs.onUpdated.addListener(function onUpdated(id, change) {
if (id === tabId && change.status === 'complete') {
browser.tabs.onUpdated.removeListener(onUpdated);
resolve();
}
});
});
}
browser.runtime.onMessage.addListener(async (msg = {}, sender) => {
if (msg.action === 'openTab') {
const tab = await browser.tabs.create({url: msg.url});
await onTabLoaded(tab.id);
await browser.tabs.sendMessage(tab.id, {
action: 'setData',
data: msg.data,
});
}
});
其他页面.html:
<!doctype html>
<p id="text"></p>
<!-- scripts at the end of the page run when DOM is ready -->
<script src="other-page.js"></script>
其他页面.js:
chrome.runtime.onMessage.addListener((msg, sender) => {
if (msg.action === 'setData') {
console.log(msg.data);
document.getElementById('text').textContent = JSON.stringify(msg.data, null, ' ');
// you can use msg.data only inside this callback
// and you can save it in a global variable to use in the code
// that's guaranteed to run at a later point in time
}
});
5. MV2/MV3:chrome.storage.local
请参阅此答案中的 chrome.storage.local 示例。
推荐阅读
- c++ - 这个函数“a::b::ptr function(value)”在c++中是如何调用的?
- javascript - 用于表的 Jquery 下拉过滤器
- office-js - Office 插件审核评论
- c# - 实体框架有一些表是唯一的,而另一些则根据客户端不同
- cmake - 使用 CTest/CMake 时在 VS2019 测试资源管理器中指定命名空间/类
- swiftui - 如何在 navigationBarItems 中对齐动态按钮
- angular - 在传单中查找距目标点最近的点
- android - 滚动视图不适用于android中的按钮
- scons - 构建 gem5 时出错:TypeError:文件 /hdd/Me/gem5/src/systemc/ext/systemc 找到预期的目录
- mysql - 这些凭据与我们的记录不匹配。在 Laravel 6 中