我正在尝试将DOM附加到从打开的自我chrome扩展文件中popup.js。假设我在chrome扩展文件中存在一个名为的文件temp.html,在执行时的某个时刻popup.js,我使用打开了该文件,chrome.tabs.create然后将DOM附加到此html文件中。
popup.js
temp.html
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),但这是一种非常round回的方法,并且在使用时从browser_action弹出窗口中,将需要在后台(active:false在chrome.tabs.create的参数中)打开选项卡,这是不可靠的,因为另一个扩展名可能会强制激活选项卡,从而关闭browser_action弹出窗口并立即终止其脚本。
active:false
一种简单/正确的方法是将数据传递到另一个页面,并通过标准通过HTML加载到该页面html中的脚本中处理数据<script src="other-page.js"></script>。
<script src="other-page.js"></script>
如果您需要在加载第一页画框之前在另一页内访问数据,请使用此选项,例如选择浅色/深色主题。您必须使用JSON’格式化非字符串类型,例如对象或数组。
劣势:如果您'storage'在扩展程序的其他页面中观察到DOM 事件,则可能会很慢。
'storage'
popup.js:
localStorage.sharedData = JSON.stringify({foo: 123, bar: [1, 2, 3], theme: 'dark'}); chrome.tabs.create({url: 'other-page.html'});
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;
缺点:地址栏中的网址太长。
chrome.tabs.create({ url: 'other-page.html?data=' + encodeURIComponent(JSON.stringify({foo: [1, 2, 3]})), });
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);
缺点1:需要后台页面。
劣势2:需要使用JSON’ification或自定义的deepClone来深克隆对象,该对象对于跨窗口上下文可以正常工作(AFAIK并不流行的deepClone会实现此条件),特别是它应该使用目标窗口的引用对象构造函数。
manifest.json:
"background": { "scripts": ["bg.js"], "persistent": false }
// 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'}); });
// 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) {}
如果您需要在后台页面中执行一系列操作(仅打开第一步),请使用此选项。例如,我们需要在第二步中传递数据。
需要背景页面,因为当在显示弹出窗口的同一窗口中打开活动选项卡时,弹出窗口将关闭并且其脚本将不再运行。可能有人认为,使用选项卡创建active: false将解决问题,但仅在用户决定安装另一种覆盖选项卡打开行为的扩展名之前才可以解决。您可能会认为您可以打开一个新窗口,但同样不能保证其他扩展程序不会将新窗口的选项卡重新附加到现有窗口中,从而关闭弹出窗口。
active: false
缺点1:在Chrome中,数据内部经过JSON’格式化,因此它使所有非标准类型(如WeakMap,TypedArray,Blob等)都受到干扰。在Firefox中,它们似乎正在使用结构化克隆,因此可以共享更多类型。
缺点2:我们两次发送相同的数据消息。
注意:我正在使用Mozilla的WebExtensionpolyfill。
"background": { "scripts": [ "browser-polyfill.min.js", "bg.js" ], "persistent": false }
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>
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 } });