欢迎光临
我们一直在努力

关于window.onload加载的七种解决方案

使用JavaScript操纵DOM,必须等待DOM加载完毕才可以执行代码,但window.onload有个坏处,它非要等到页面中的所有图片及视频加载完毕才会触发load事件。结果就是一些本来应该在打开时隐藏起来的元素,由于网络延迟,在页面打开时仍然会出现,然后又会突然消失,让用户觉得莫名其妙。我们想做的就是寻找一种方法来确定DOM被完全的加载时不用等待所有那些讨厌的图片加载完毕。必须与这种丑陋的闪烁告别!

我这里整理出针对onload事件的七种方案。

第七种方案是我们最终的解决方案,也是完美的解决方案。

三 ~ 六 的解决方案只解决了window.onload加载多个方法,但是还没有解决图片的等待加载问题,还有它们只兼容IE和FF。

最成熟的解决:http://javascript.nwbox.com/ContentLoaded/

定义和用法
onload 事件会在页面或图像加载完成后立即发生。

语法

onload=”SomeJavaScriptCode”

支持该事件的 HTML 标签:

<body>, <frame>, <frameset>, <iframe>, <img>, <link>, <script>

支持该事件的 JavaScript 对象:

image, layer, window实例

第一种:

function loadFunction(){ 
alert("hello!");
}


<body onload="loadFunction()">

第二种:

window.onload = loadFunction; 
function loadFunction(){ 
alert("hello!");
}

第三种:

function firstFunction(){
alert("hello firstFun !");
}
function secondFunction(){
alert("hello secondFun !");

}
window.onload = function(){ 
firstFunction(); 
secondFunction(); 
}

第四种:通用的做法

function firstFunction() {
    alert("hello firstFun !");
}
function secondFunction() {
    alert("hello secondFun !");

}

function addLoadEvent(func) {
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {
        window.onload = func;
    } else {
        window.onload = function () {
            oldonload();
            func();
        }
    }
}

//测试 
addLoadEvent(firstFunction);
addLoadEvent(secondFunction);

addLoadEvent工作流程:

把现有的window.onload事件处理函数的值存入变量oldonload。

如果在这个处理函数上还没有绑定任何函数,就像平时那样把新函数添加给它;

如果在这个处理函数已经绑定了一些函数,就把函数追回到现有指令未尾。

浏览器加载html内容是自上而下的(默认),而JS一般是在哪里引入——想想如果JS里面包含了一些即时执行指令,

它会操作根本不存在元素节点(因为还没有加载完)会有什么后果?结果就是出错。

addLoadEvent可以实现无论有多少个函数,都能让它们同时和window.onload事件绑定。

第五种; 推荐

function a(){
    alert("a");
}

function b(){
    alert("b");
}


function addEvent(obj,EventName,callBack){//给对象添加事件 
    if(obj.addEventListener){ //FF
        obj.addEventListener(EventName,callBack,false);
    }else if(obj.attachEvent){//IE 
        obj.attachEvent('on'+EventName,callBack);
    }else{
        obj["on"+EventName]=callBack;
    }
}
//测试 
addEvent(window,"load",a);
addEvent(window,"load",b);

第六种:推荐

function a(){
    alert("a");
}

function b(){
    alert("b");
}
// Please note: this file contains snippets for comparison 
// it is not self-contained or ready-to-use code as such 
function addLoadListener(fn)
{
    if (typeof window.addEventListener != 'undefined')
    {
        window.addEventListener('load', fn, false);
    }
    else if (typeof document.addEventListener != 'undefined')
    {
        document.addEventListener('load', fn, false);
    }
    else if (typeof window.attachEvent != 'undefined')
    {
        window.attachEvent('onload', fn);
    }
    else
    {
        var oldfn = window.onload;
        if (typeof window.onload != 'function')
        {
            window.onload = fn;
        }
        else
        {
            window.onload = function()
            {
                oldfn();
                fn();
            };
        }
    }
}

//测试
addLoadListener(a);
addLoadListener(b);

第七种:最完美的解决方案

建立一个独立的通用解决方案,兼容各种浏览器,任何人都可以使用,而无需一个具体的框架。

最初的完整解决方案:http://dean.edwards.name/weblog/2006/06/again/

一个独立的通用解决方案 :http://www.thefutureoftheweb.com/blog/adddomloadevent.

/*
 * (c)2006 Jesse Skinner/Dean Edwards/Matthias Miller/John Resig
 * Special thanks to Dan Webb's domready.js Prototype extension
 * and Simon Willison's addLoadEvent
 *
 * For more info, see:
 * http://www.thefutureoftheweb.com/blog/adddomloadevent
 * http://dean.edwards.name/weblog/2006/06/again/
 * http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype
 * http://simon.incutio.com/archive/2004/05/26/addLoadEvent
 * 
 *
 * To use: call addDOMLoadEvent one or more times with functions, ie:

 * addDOMLoadEvent的调用方法,如下:
 * function something() {
 * // do something
 * }
 * addDOMLoadEvent(something);
 *
 * addDOMLoadEvent(function() {
 * // do other stuff
 * });
 *
 */

addDOMLoadEvent = (function(){

// create event function stack
    var load_events = [],
        load_timer,
        script,
        done,
        exec,
        old_onload,
        init = function () {
            done = true;
            /*//停止调用计时器*/
// kill the timer
            clearInterval(load_timer);

// execute each function in the stack in the order they were added
            while (exec = load_events.shift())
                exec();

            if (script) script.onreadystatechange = '';
        };

    return function (func) {
// if the init function was already ran, just run this function now and stop
        if (done) return func();

        if (!load_events[0]) {

// for Mozilla/Opera9
            /* 
             DOMContentLoaded是firefox下特有的Event, 当所有DOM解析完以后会触发这个事件。
             注册DOMContentLoaded事件,如果支持的话
             */
            if (document.addEventListener)
                document.addEventListener("DOMContentLoaded", init, false);

// for Internet Explorer
            /*
             对于IE则使用条件注释,并使用script标签的defer属性
             IE中可以给script标签添加一个defer(延迟)属性,这样,标签中的脚本只有当DOM加载完毕后才执行*/

            /*@cc_on @*/
            /*@if (@_win32)
             document.write("<script id=__ie_onload defer src=//0><\/scr"+"ipt>");
             script = document.getElementById("__ie_onload");
             script.onreadystatechange = function() {
             if (this.readyState == "complete")
             init(); // call the onload handler
             };
             /*@end @*/

// for Safari
            /*
             但对于Safari,我们需要使用setInterval方法不断检测document.readyState
             当为loaded或complete的时候表明DOM已经加载完毕 
             */

            if (/WebKit/i.test(navigator.userAgent)) { // sniff
                load_timer = setInterval(function() {
                    if (/loaded|complete/.test(document.readyState))
                        init(); // call the onload handler
                }, 10);
            }

// for other browsers set the window.onload, but also execute the old window.onload
            old_onload = window.onload;
            window.onload = function() {
                init();
                if (old_onload) old_onload();
            };
        }

        load_events.push(func);
    }
})();

方案七的演示:

http://blog.moocss.com/Project/JavaScript/demo4/addDOMLoadEvent-Demo-Page.htm
addDOMLoadEvent 原始文件:http://blog.moocss.com/Project/JavaScript/demo4/adddomloadevent-compressed.js
addDOMLoadEvent 压缩版文件:http://blog.moocss.com/Project/JavaScript/demo4/adddomloadevent-compressed.js

最成熟的解决方案:

第七种方案回头看,源码中的 hacks 用的太多,也并不完美,接下来,就看一个大家都在用的:

/*!
 * contentloaded.js
 *
 * Author: Diego Perini (diego.perini at gmail.com)
 * Summary: cross-browser wrapper for DOMContentLoaded
 * Updated: 20101020
 * License: MIT
 * Version: 1.2
 *
 * URL:
 * http://javascript.nwbox.com/ContentLoaded/
 * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
 *
 */

// @win window reference
// @fn function reference
(function(win, doc) {
    contentLoaded=function(fn) {
        var done = false, top = true,

            doc = win.document, root = doc.documentElement,

            add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
            rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
            pre = doc.addEventListener ? '' : 'on',

            init = function(e) {
                if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
                (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
                if (!done && (done = true)) fn.call(win, e.type || e);
            },

            poll = function() {
                try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
                init('poll');
            };

        if (doc.readyState == 'complete') fn.call(win, 'lazy');
        else {
            if (doc.createEventObject && root.doScroll) {
                try { top = !win.frameElement; } catch(e) { }
                if (top) poll();
            }
            doc[add](pre + 'DOMContentLoaded', init, false);
            doc[add](pre + 'readystatechange', init, false);
            win[add](pre + 'load', init, false);
        }

    }
})(window, document);
<pre>
<h3>使用方法:</h3>
<pre lang="javascript" line="1">
//测试
var $tt = (new Date).getTime();
function timeElapsed(t) { return ((new Date()).getTime() - t); }
contentLoaded(
    function (e) {
        document.body.style.backgroundColor = 'green';
        window.status =
            window.defaultStatus =
                ' * ' + (e.type || e) + ' ' +
                ' - ' + (e.eventType ? e.eventType : 'native') +
                ' in ' + timeElapsed($tt) + ' ms.';
    }
);

//测试
contentLoaded(
    function(){
        var el=document.getElementById('logo');
        console.log(el);
    }
);

 

赞(0)
版权归原作者所有,如有侵权请告知。达维营-前端网 » 关于window.onload加载的七种解决方案

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址