从弹出窗口打开时,修改带有扩展HTML文件的选项卡

时间:2019-02-15 11:38:15

标签: javascript google-chrome-extension

我正在尝试将DOM附加到从popup.js打开的自我chrome扩展文件中。 假设我有一个Chrome扩展文件中存在一个名为temp.html的文件,在执行popup.js的某个时候,我使用chrome.tabs.create打开了此文件,然后我想向此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

1 个答案:

答案 0 :(得分:2)

尽管您可以使用chrome.extension.getViews直接访问在新标签页中打开的扩展程序页面的DOM,但这需要在后台打开标签页({。{1}}在chrome.tabs.create参数中),这是不可靠的,因为另一个扩展名可能会强制激活选项卡,从而关闭您的弹出窗口,从而立即终止您的弹出脚本。

正确的方法是将数据传递到另一个页面,并通过标准active:false处理在该页面html中加载的脚本中的数据。

1。通过HTML5 localStorage +同步访问共享

如果在第一个绘制框架之前的另一页内加载期间需要访问数据,例如选择一个浅色/深色主题。您必须使用JSON'格式化非字符串类型,例如对象或数组。

缺点:如果您在扩展程序的其他页面中观察到DOM <script src="other-page.js"></script>事件,可能会很慢。

popup.js:

'storage'

other-page.js:

localStorage.sharedData = JSON.stringify({foo: 123, bar: [1, 2, 3], theme: 'dark'});
chrome.tabs.create({url: 'other-page.html'});

2。通过URL参数共享+同步访问

如果在第一个绘制框架之前的另一页内加载期间需要访问数据,例如选择一个浅色/深色主题。您必须使用JSON'格式化非字符串类型,例如对象或数组。

缺点:地址栏中的网址很长。

popup.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;

other-page.js:

chrome.tabs.create({
  url: 'other-page.html?data=' + encodeURIComponent(JSON.stringify({foo: [1, 2, 3]})),
});

3。通过后台页面共享全局变量+同步访问

如果在第一个绘制框架之前的另一页内加载期间需要访问数据,例如选择一个浅色/深色主题。您必须使用JSON'格式化非字符串类型,例如对象或数组。

缺点1:需要背景页面。

缺点2:需要通过使用JSON'化或自定义的deepClone来深克隆对象,该对象对于跨窗口上下文可以正常工作(AFAIK并不流行的deepClone都实现此条件),特别是它应该使用目标窗口的对象构造函数的引用。

manifest.json:

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);

popup.js:

"background": {
  "scripts": ["bg.js"],
  "persistent": false
}

other-page.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'});
});

4。通过背景页面消息传递以两跳方式共享

如果您需要在后台页面中执行一系列操作,则仅需打开其标签即可使用。例如,我们需要在第二步中传递数据。

需要背景页面,因为当在显示弹出窗口的同一窗口中打开活动选项卡时,弹出窗口将关闭并且其脚本将不再运行。有人可能会认为,使用// 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) {} 创建选项卡可以解决问题,但仅在用户决定安装另一个扩展选项卡打开行为的扩展名之前才可以解决。您可能会认为您可以打开一个新窗口,但同样不能保证其他扩展程序不会将新窗口的选项卡重新附加到现有窗口中,从而关闭弹出窗口。

缺点1:在Chrome中,数据内部经过JSON修饰,因此它使所有非标准类型(如WeakMap,TypedArray,Blob等)都受到干扰。在Firefox中,它们似乎正在使用结构化克隆,因此可以共享更多类型。

>

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

注意:我正在使用Mozilla's WebExtension polyfill

manifest.json:

active: false

popup.js:

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

bg.js:

chrome.runtime.sendMessage({
  action: 'openTab',
  url: '/other-page.html',
  data: {foo: 123, bar: [1, 2, 3], theme: 'dark'},
});

other-page.html:

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.js:

<!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。通过chrome.storage.local分享

请参阅this answer中chrome.storage.local的示例。