使用JavaScript操纵DOM,必须等待DOM加载完毕才可以执行代码,但window.onload有个坏处,它非要等到页面中的所有图片及视频加载完毕才会触发load事件。结果就是一些本来应该在打开时隐藏起来的元素,由于网络延迟,在页面打开时仍然会出现,然后又会突然消失,让用户觉得莫名其妙。我们想做的就是寻找一种方法来确定DOM被完全的加载时不用等待所有那些讨厌的图片加载完毕。必须与这种丑陋的闪烁告别!
我这里整理出针对onload事件的七种方案。
第七种方案是我们最终的解决方案,也是完美的解决方案。
三 ~ 六 的解决方案只解决了window.onload加载多个方法,但是还没有解决图片的等待加载问题,还有它们只兼容IE和FF。
定义和用法
onload 事件会在页面或图像加载完成后立即发生。
语法
onload=”SomeJavaScriptCode”
支持该事件的 HTML 标签:
1 |
<body>, <frame>, <frameset>, <iframe>, <img>, <link>, <script> |
支持该事件的 JavaScript 对象:
image, layer, window实例
第一种:
1 2 3 |
function loadFunction(){ alert("hello!"); } |
1 |
<body onload="loadFunction()">
|
第二种:
1 2 3 4 |
window.onload = loadFunction; function loadFunction(){ alert("hello!"); } |
第三种:
1 2 3 4 5 6 7 8 9 10 11 |
function firstFunction(){ alert("hello firstFun !"); } function secondFunction(){ alert("hello secondFun !"); } window.onload = function(){ firstFunction(); secondFunction(); } |
第四种:通用的做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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事件绑定。
第五种; 推荐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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); |
第六种:推荐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
/* * (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); } })(); |