IT虾米网

火狐扩展 : share state

shasha 2025年05月04日 程序员 1257 0

我有一个 Firefox 覆盖扩展,侧边栏中有一棵树。 如何在多个窗口中保持树状态同步? 例如在第一个窗口中在树中添加了新项目,如何更新其他窗口中的树?

如果有人可以展示最少的代码(使用代码模块、观察者、广播者或其他东西),请提供帮助。

我读过类似的问题,但没有帮助: Firefox extension - Share common state between two or more windows

请您参考如下方法:

您提到的问题的答案很好,但解释不够。您应该阅读它链接的引用文献。我已在此处复制了这些链接。

将状态信息保留在窗口上下文之外的一种方法是使用 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 保留对数据结构中对象的引用,所有侧边栏都在该对象上放置监听器。这可能是它创建的一个对象。如果您确实使用此方法并选择使用窗口,那么您需要确保在窗口关闭时句柄释放引用。如果不这样做,可能会导致内存泄漏。


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!