Javascript 在新选项卡/窗口中传递数据或修改扩展html

Javascript 在新选项卡/窗口中传递数据或修改扩展html,javascript,google-chrome-extension,Javascript,Google Chrome Extension,我试图将DOM附加到从popup.js打开的自chrome扩展文件中。 假设我在chrome扩展文件中有一个名为temp.html的文件,在执行popup.js时,我使用chrome.tabs打开了这个文件。创建然后我想在这个html文件中附加一个DOM 我是否可以通过popup.js这样做 Extension files: 1-manifest.json 2-functions functions.js domToTables.js 3-libs jquery-3.3

我试图将DOM附加到从
popup.js
打开的自chrome扩展文件中。 假设我在chrome扩展文件中有一个名为
temp.html
的文件,在执行
popup.js
时,我使用
chrome.tabs打开了这个文件。创建
然后我想在这个html文件中附加一个DOM

我是否可以通过
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(如果使用window.open,则更简单)直接访问在新选项卡/窗口中打开的扩展页面的DOM,但这是UI原始时的方法,因此如果打开的页面使用表示框架,则无法工作。此外,当从弹出窗口使用时,您必须首先在后台打开选项卡(“chrome.tabs.create”参数中的
active:false
),否则弹出窗口将自动关闭,因此不会运行进一步的代码,不幸的是,这仍然不可靠,因为另一个扩展可能会强制激活选项卡

可靠/正确的方法是将数据传递到另一个页面,并让它处理通过标准
加载到该页面html中的脚本中的数据

1.MV2:HTML5本地存储+同步访问 如果您需要在加载过程中在第一个画框之前访问其他页面内的数据,例如选择浅/暗主题,请使用此选项

缺点:大量数据可能会显著降低预算设备的速度,您必须将非字符串类型(如对象或数组)JSON化

popup.js:

localStorage.sharedData = JSON.stringify({foo: 123, bar: [1, 2, 3], theme: 'dark'});
chrome.tabs.create({url: 'other-page.html'});
chrome.tabs.create({
  url: 'other-page.html?data=' + encodeURIComponent(JSON.stringify({foo: [1, 2, 3]})),
});
// 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'});
});
chrome.runtime.sendMessage({
  action: 'openTab',
  url: '/other-page.html',
  data: {foo: 123, bar: [1, 2, 3], theme: 'dark'},
});
other-page.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;
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);
// 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) {}
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
  }
});

2.MV2/MV3:URL参数+同步访问 如果您需要在加载过程中在第一个画框之前访问其他页面内的数据,例如选择浅/暗主题,请使用此选项

缺点:地址栏中有一个很长的url,您必须对对象或数组等非字符串类型使用JSON

popup.js:

localStorage.sharedData = JSON.stringify({foo: 123, bar: [1, 2, 3], theme: 'dark'});
chrome.tabs.create({url: 'other-page.html'});
chrome.tabs.create({
  url: 'other-page.html?data=' + encodeURIComponent(JSON.stringify({foo: [1, 2, 3]})),
});
// 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'});
});
chrome.runtime.sendMessage({
  action: 'openTab',
  url: '/other-page.html',
  data: {foo: 123, bar: [1, 2, 3], theme: 'dark'},
});
other-page.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;
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);
// 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) {}
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
  }
});

3.MV2:后台脚本的全局变量+同步访问 如果您需要在加载过程中在第一个画框之前访问其他页面内的数据,例如选择浅/暗主题,请使用此选项

缺点1:需要一个背景页

缺点2:需要通过使用JSON.parse(JSON.stringify(data))或适用于跨窗口上下文的自定义deepClone对对象进行深度克隆,因为没有流行的deepClone实现可以做到这一点:具体来说,它应该使用对象构造函数的target
window
引用

manifest.json:

"background": {
  "scripts": ["bg.js"],
  "persistent": false
}
"background": {
  "scripts": [
    "browser-polyfill.min.js",
    "bg.js"
  ],
  "persistent": false
}
popup.js:

localStorage.sharedData = JSON.stringify({foo: 123, bar: [1, 2, 3], theme: 'dark'});
chrome.tabs.create({url: 'other-page.html'});
chrome.tabs.create({
  url: 'other-page.html?data=' + encodeURIComponent(JSON.stringify({foo: [1, 2, 3]})),
});
// 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'});
});
chrome.runtime.sendMessage({
  action: 'openTab',
  url: '/other-page.html',
  data: {foo: 123, bar: [1, 2, 3], theme: 'dark'},
});
other-page.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;
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);
// 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) {}
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
  }
});

4.MV2/MV3:后台脚本在两个跃点中中继消息传递 如果需要在后台页面中执行一系列操作(打开选项卡只是第一步),请使用。例如,我们需要在第二步中传递数据

需要背景页面,因为当在显示弹出窗口的同一窗口中打开活动选项卡时,弹出窗口将关闭,其脚本将不再运行。有人可能会认为,创建一个带有
active:false
的选项卡可以解决问题,但只有在用户决定安装另一个覆盖选项卡打开行为的扩展之前。您可能会认为您可以打开一个新窗口,但同样不能保证其他扩展不会将新窗口的选项卡重新附加到现有窗口中,从而关闭弹出窗口

缺点1:在Chrome中,数据是内部JSON化的,因此它会屏蔽所有非标准类型,如WeakMap、TypedArray、Blob等。在Firefox中,他们似乎使用结构化克隆,因此可以共享更多类型

缺点2:我们发送相同的数据消息两次

注意:我正在使用

manifest.json:

"background": {
  "scripts": ["bg.js"],
  "persistent": false
}
"background": {
  "scripts": [
    "browser-polyfill.min.js",
    "bg.js"
  ],
  "persistent": false
}
popup.js:

localStorage.sharedData = JSON.stringify({foo: 123, bar: [1, 2, 3], theme: 'dark'});
chrome.tabs.create({url: 'other-page.html'});
chrome.tabs.create({
  url: 'other-page.html?data=' + encodeURIComponent(JSON.stringify({foo: [1, 2, 3]})),
});
// 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'});
});
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,
    });
  }
});
other-page.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>

5.MV2/MV3:chrome.storage.local
请参阅中chrome.storage.local的示例。

以进行说明。这是您的扩展中的一个页面还是某个网页?您可以使用chrome.extension.getViews(假设选项卡以active:false打开),但正确的方法通常是发送消息,让页面本身在通过标准
加载的脚本中处理它。我将尝试找到一个现有的答案,应该有很多……或者使用存储而不是消息传递:那么我同意wOxxOm的评估。链接的问题应该概述你需要做什么(使用消息)。@wOxxOm,谢谢,我将尝试你的方法。我非常感谢你的详细评论,因为它为我打开了更多的潜力。我使用了第四种方法——对于像我这样的新手来说这更容易理解——并且奏效了。明天我将尝试方法5,谢谢。