您的位置:首页 > 其它

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

2015-11-05 10:31 661 查看
转自:http://blog.moocss.com/tutorials/javascript-tutorials/526.html (Blog也不错,可以看看)

By Rainbow on 2009-07-24 // JavaScript
// 4219 Views+ // (5)Comments

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

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

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

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

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

定义和用法

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

语法

onload=”SomeJavaScriptCode”

支持该事件的 HTML 标签:

1

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

支持该事件的 JavaScript 对象:

image, layer, window实例


第一种:

12
3

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

1

<body onload="loadFunction()">


第二种:

12
3
4

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


第三种:

12
3
4
5
6
7
8
9
10
11

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

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


第四种:通用的做法

12
3
4
5
6
7
8
9
10
1112
13
14
15
16
17
18
19
20
2122
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事件绑定。


第五种; 推荐

12
3
4
5
6
7
8
9
10
1112
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);


第六种:推荐

12
3
4
5
6
7
8
9
10
1112
13
14
15
16
17
18
19
20
2122
23
24
25
26
27
28
29
30
3132
33
34
35
36
37
38
39
40
4142
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.

12
3
4
5
6
7
8
9
10
1112
13
14
15
16
17
18
19
20
2122
23
24
25
26
27
28
29
30
3132
33
34
35
36
37
38
39
40
4142
43
44
45
46
47
48
49
50
5152
53
54
55
56
57
58
59
60
6162
63
64
65
66
67
68
69
70
7172
73
74
75
76
77
78
79
80
8182
83
84
85
86
87
88
89
90
9192
93
94
95
96
97
98
99
100
101102

/*
* (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 用的太多,也并不完美,接下来,就看一个大家都在用的:

12
3
4
5
6
7
8
9
10
1112
13
14
15
16
17
18
19
20
2122
23
24
25
26
27
28
29
30
3132
33
34
35
36
37
38
39
40
4142
43
44
45
46
47
48
49
50
5152
53
54
55
56
57
58
59
60
6162
63
64
65
66
67
68
69
70
7172
73
74
75

/*!
* 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);
}
);

This entry was posted in JavaScript and tagged Tags: JavaScript, JavaScript基础.
Bookmark thepermalink
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: