在页面完全加载后加载脚本

时间:2012-05-22 15:38:47

标签: firefox-addon

我正在构建一个firefox插件,可以在每个页面加载时加载javascript。我正在使用我在此页面上找到的进度监听器功能: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 个答案:

答案 0 :(得分: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);

尚未测试,但应该有效。

答案 1 :(得分: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()不同,后者有第二个参数。

答案 2 :(得分: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");

  },
};

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

答案 3 :(得分:-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);