我有一个Firefox覆盖扩展,侧边栏中有一棵树。 如何在多个窗口中保持树状态同步? 例如在第一个窗口中添加了树中的新项,如何在其他窗口中更新树?
如果某人可以显示最少的代码(使用代码模块,观察者,广播公司或其他东西),请帮助。
我读了类似的问题,但没有帮助: Firefox extension - Share common state between two or more windows
答案 0 :(得分:1)
你提到的问题的答案是好的,但解释不够。您应该阅读它链接的引用。我在这里重复了这些链接。
将状态信息保留在窗口上下文之外的一种方法是使用JavaScript code modules(JSM)。 Sharing objects using code modules部分简要介绍了如何做到这一点。一旦设置了JSM来共享数据,只需告知每个窗口已经进行了更改并且应该更新显示的状态。通过使用您定义的事件可以轻松完成此操作。所有侧边栏都会在窗口中监听特定事件。然后在JSM中有一个函数,它运行所有窗口,通知它们需要更新它们。
信号代码可能类似于:
Components.utils.import("resource://gre/modules/Services.jsm");
function forEachOpenWindow(todo) {
// Apply a function to all open browser windows
var windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
todo(windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow));
}
}
function signalUpdateNeeded(window){
let event = window.document.createEvent("Event");
event.initEvent("myExtensionName-UpdateAvailable",false,false);
window.dispatchEvent(event);
}
function sendUpdateAvailableToAllWindows(){
forEachOpenWindow(signalUpdateNeeded);
}
然后在侧边栏的代码中:
//This imports your JSM, it does not need the .jsm extension, you can use
// whatever extension you want.
Components.utils.import("chrome://MyExtension/content/moduleName.jsm");
window.addEventListener("myExtensionName-UpdateAvailable",
updateDataFromModule, false);
//Instead you may need the following (or another way to get to the
// top window). What is actually needed will depend on the context in
// which your sidebar code is running. You should see below for code to
// access the main browser window from within a sidebar.
//window.top.addEventListener("myExtensionName-UpdateAvailable",
// updateDataFromModule, false);
function updateDataFromModule(){
//Whatever it is you need to do here.
mylocalVariable = myExtensionModule.dataStructure.whatever;
}
重构上面的第一个代码部分,使它看起来像是在一个使用一个变量来减少命名空间混乱的模块中。该模块的代码可能类似于:
var EXPORTED_SYMBOLS = [ "myExtensionModule" ];
Components.utils.import("resource://gre/modules/Services.jsm");
var myExtensionModule = {
dataStructure: {
whatever: true,
you: 1,
want: ["here.", "It", "is", "your", "data."]
};
forEachOpenWindow: function(todo){
// Apply a function to all open browser windows
var windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
todo(windows.getNext()
.QueryInterface(Components.interfaces.nsIDOMWindow));
}
},
signalUpdateNeeded: function(window){
let event = window.document.createEvent("Event");
event.initEvent("myExtensionName-UpdateAvailable",false,false);
window.dispatchEvent(event);
},
sendUpdateAvailableToAllWindows: function(){
this.forEachOpenWindow(this.signalUpdateNeeded);
}
}
我实际上没有对此进行测试,因此可能存在一些错误。
让您的侧边栏代码访问主浏览器窗口,或者JSM代码找到您的代码所在的侧边栏(为了发送或收听事件)可能比您想象的要复杂一些。你应该看到Working with windows in chrome code。具体而言,Accessing the elements of the top-level document from a child window。该部分提供以下代码以从侧边栏访问主浏览器窗口:
var mainWindow = window
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
另一种方法是让您的JSM保持对数据结构中对象的引用,所有侧边栏都放置在该对象上。这可能是它创建的对象。如果您确实使用此方法并选择使用窗口,则需要确保在窗口关闭时释放引用的句柄。如果你不这样做,你最终可能会发生内存泄漏。