1

我正在构建一个在每个页面加载时加载 javascript 的 Firefox 插件。我正在使用在此页面上找到的进度侦听器功能: https ://developer.mozilla.org/en/Code_snippets/Progress_Listeners

我的问题是代码似乎在页面完全加载之前执行到早期,这导致我的脚本无法运行。这是我的代码。

var PageLoad = {
    browser: null,
    domain:  null,
    oldURL:  null,

    init: function() {
            gBrowser.addProgressListener(urlBarListener,Components.interfaces.nsIWebProgress.NOTIFY_LOCATION);
    },

    uninit: function() {
            gBrowser.removeProgressListener(urlBarListener);
    },

    processNewURL: function(aURI) {
            //if (aURI.spec == this.oldURL)
            //return;

        MyObject.function();

            this.oldURL = aURI.spec;
    }
};

var urlBarListener = {
    locChange: false,

    QueryInterface: function(aIID) {
            if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
               aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
               aIID.equals(Components.interfaces.nsISupports))
            return this;
            throw Components.results.NS_NOINTERFACE;
    },

    onLocationChange: function(aProgress, aRequest, aURI) {
            PageLoad.processNewURL(aURI);
    },

    onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) {},
    onProgressChange: function(a, b, c, d, e, f) {},
    onStatusChange: function(a, b, c, d) {},
    onSecurityChange: function(a, b, c) {}
};

window.addEventListener("load",
    function() {
            PageLoad.init()
    }, false);

var MyObject = {
    function : function() {
            var script = PageLoad.browser.createElement('script');
            script.src = 'url_to_script.js';
            PageLoad.browser.getElementsByTagName('head')[0].appendChild(script);
    }
};

使用此代码,我在控制台上收到此错误消息:

PageLoad.browser.getElementByTagName("head")[0] 未定义

如果我添加超时,那么脚本会间歇性地工作,但如果页面加载缓慢,我会遇到同样的错误,这就是有时有效的方法setTimeout(MyObject.function, 1000);

我需要一种更可靠的方法来确保它在页面加载后执行脚本。

不相关,它似乎不会导致任何问题,但我也看到此错误消息:

gBrowser.addProgressListener 使用第二个参数调用,这是不受支持的。请参阅错误 608628。

4

4 回答 4

2

如果您想在每个页面加载时加载 javascript - 最好的方法是订阅DOMContentLoaded事件:

var MyObject  = {
    processDOMContentLoaded: function(doc) {
        var script = doc.createElement('script');
        script.src = 'url_to_script.js';
        script.type = 'text/javascript';
        doc.getElementsByTagName('head')[0].appendChild(script);
    }
};

window.addEventListener('load', function() {
    var appcontent = document.getElementById('appcontent');
    if(appcontent != null) {
        appcontent.addEventListener('DOMContentLoaded', function(event) {
            var doc = event.originalTarget;
            if(doc instanceof HTMLDocument) {
                MyObject.processDOMContentLoaded(doc);
            }
        }, true);
    }
}, false);

尚未测试,但应该可以工作。

于 2012-05-22T19:07:22.100 回答
1

您正在使用onLocationChange方法 - 但如果您查看浏览器的行为方式,地址栏中的位置会在与服务器建立连接后立即更改。您应该查看状态更改:

onStateChange: function(aWebProgress, aRequest, aFlag, aStatus)
{
  if ((aFlag & Components.interfaces.nsIWebProgressListener.STATE_STOP) &&
      (aFlag & Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW))
  {
    // A window finished loading
    PageLoad.windowLoaded(aWebProgress.DOMWindow);
  }
},

请注意,完成加载的窗口被显式传递给PageLoad.windowLoaded()- 您将收到来自不同选项卡的通知,并且您不能假设通知来自前台选项卡。

至于您收到的警告,只需在调用中省略第二个参数gBrowser.addProgressListener()

gBrowser.addProgressListener(urlBarListener);

tabbrowser.addProgressListener()只接受一个参数,不像nsIWebProgress.addProgressListener()它有第二个参数。

于 2012-05-22T18:55:09.553 回答
1

实际上这是一个很好的问题。您应该使用事件监听器,但要小心,因为如果您为每个页面加载触发它可能会触发您多次(在最坏的情况下大约几十次)。那你怎么能做到呢?

window.addEventListener("load", function load(event){
    window.removeEventListener("load", load, false); //remove listener, no longer needed
    myExtension.init(); 
},false);

var myExtension = {
    init: function() {
    var appcontent = document.getElementById("appcontent");   // browser
    if(appcontent){
      appcontent.addEventListener("DOMContentLoaded", myExtension.onPageLoad, true);
    }

  },

  onPageLoad: function(aEvent) {
    var doc = aEvent.originalTarget; // doc is document that triggered the event
    var win = doc.defaultView; // win is the window for the doc

    if (doc.nodeName != "#document") return;
    if (win != win.top) return;
    if (win.frameElement) return;

      alert("the main page has been loaded");

  },
};

请注意,我们会在每次页面加载触发时检查触发器的类型,以防止多重加载。

于 2013-04-08T06:30:48.483 回答
-1

提供的答案是可以接受的,但我找到了另一个完美的解决方案。

var PageLoad = {
init: function() {
    if(gBrowser) gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad, false);
  },
  onPageLoad: function(aEvent) {
    var doc = aEvent.originalTarget; // doc is document that triggered the event
    var win = doc.defaultView; // win is the window for the doc

    if (doc.nodeName != "#document") return;
    if (win != win.top) return;
    if (win.frameElement) return;

    MyAddon.function();
  }
}

window.addEventListener("load", function load(event){
  window.removeEventListener("load", load, false); //remove listener, no longer needed
  PageLoad.init();  
},false);
于 2012-05-23T17:45:49.203 回答