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

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

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

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

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

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

语法

οnlοad=”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) ;
}
} ) ( ) ;

 

方案七的演示:

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值