WEB开发网
开发学院网页设计JavaScript javascript的事件加载 阅读

javascript的事件加载

 2009-08-26 20:13:20 来源:WEB开发网   
核心提示:通常来说,window.onload就够用了,javascript的事件加载,如果想加载多个事件,我们可以采取以下方式:1.window.onload = function(){ 2. func1(); 3. func2(); 4. func3(); 5. //更多加载事件……………… 6.}但如果由于某种特殊需要,假

通常来说,window.onload就够用了,如果想加载多个事件,我们可以采取以下方式:

1.window.onload = function(){
2.   
func1();
3.   
func2();
4.   
func3();
5.   
//更多加载事件………………
6.}
但如果由于某种特殊需要,我们不能合在一起写吗?如当前区域是面向管理员,后台生成页面时只有当用户是管理员,页面才生成这部分,而这部分也用到一些特殊的脚本,上面的方法就歇菜了!

01.//后台代码
02.<script type="text/javascript">
03.   
window.onload = function(){
04.    
func1();
05.    
func2();
06.    
//加载普通用户用到的脚本……
07.   
}
08.</script>
09.<%# 以下脚本是为管理员准备的 %>
10.<% if @user.role == "manager"  %>
11.   
window.onload = function(){
12.   
func1();
13.   
func2();
14.   
//加载机密脚本……
15.   
}
16.<% end %>
这种情况生成出来的页面拥有两个window.onload代码块,很显然,第二个覆盖掉第一个。这时,轮到loadEvent函数出场了。

01.var loadEvent = function(fn) {
02.  
var oldonload = window.onload;
03.  
if (typeof window.onload != 'function') {
04.    
window.onload = fn();
05.  
}else {
06.    
window.onload = function() {
07.      
oldonload();
08.      
fn();
09.    
}
10.  
}
11.}
它非常完美地解决了互相覆盖的问题,用法如下:

1.loadEvent(func1);
2.loadEvent(func2);
3.loadEvent(func3);
4.//更多加载事件
但现实的问题总是如此出奇不意,也如此刁钻邪门。最近我想把所有的函数放到一个闭包中,以免除命名冲突之苦,比如那个有名的$的DOM选择器。JQuery,PRototype,mootool都用它做选择器的名字,共存成了个严重的问题。

01.(function(){
02.  
if(!window.JS){
03.    
window['JS'] = {}
04.  
}
05.  
var onReady = function(fn){
06.    
var oldonload = window.onload;
07.    
if (typeof window.onload != 'function') {
08.      
window.onload = fn();
09.    
}else {
10.      
window.onload = function() {
11.        
oldonload();
12.        
fn();
13.      
}
14.    
}
15.  
}
16.  
JS.onReady = onReady;
17.  
var $ = function(id){
18.    
return document.getElementById(id);
19.  
}
20.  
JS.$ = $;
21.})()<!doctype html>
<html dir="ltr" lang="zh-CN">
  <head>
   <meta charset="utf-8"/>
   <meta http-equiv="X-UA-Compatible" content="IE=Edge">
   <title>闭包环境中的事件加载</title>
   <script type="text/Javascript">
    (function(){
     if(!window.JS){
      window['JS'] = {}
     }
     var onReady = function(fn){
      var oldonload = window.onload;
      if (typeof window.onload != 'function') {
       window.onload = fn();
      }else {
       window.onload = function() {
        oldonload();
        fn();
       }
      }
     }
     JS.onReady = onReady;
     var $ = function(id){
      return document.getElementById(id);
     }
     JS.$ = $;
    })()
    JS.onReady(function(){
     var $ = JS.$;
     try{
     alert($("test").innerHTML);
     }catch(e){
      alert(e);
     }
    })
   </script>
  </head>
  <body>
   <p id="test">Test</p>
  </body>
</html>
 
运行代码

报错,说找不到节点。为什么找不到呢?因为我们在调用它的时候,DOM树还没有建立起来!不会吧,网页是如此完整地显示我们眼前了。这与闭包的运作有关,当JS引擎解析到闭包的最后一个“}”,就把里面的东西锁到一个密封的环境中,JS继续向下执行,就修正不了闭包中的window的属性了。window有一个出名的属性,叫做document,它引用着整个DOM树(当然还有其他操作)。DOM树是一个复杂的键值对,当JS不断向下解析时,就不断往document添加相应的节点。但当它塞进闭包后,里面的时间就静止了,因此它还停留在解析head的阶段,document是残缺的,想获取body中的节点,当然是返回null了。于是问题的关键是如何让闭包内的document重新继续向下解析。 方法有两个,一个是利用侦听器(addEventListener与attachEvent),一个是利用基于时间轴的setTimeout与setInterval。

01.(function(){
02.  
if(!window.JS){
03.    
window['JS'] = {}
04.  
}
05.  
var addEvent = function( obj, type, fn ) {
06.    
if (obj.addEventListener)
07.      
obj.addEventListener( type, fn, false );
08.    
else if (obj.attachEvent) {
09.      
obj["e"+type+fn] = fn;
10.      
obj.attachEvent( "on"+type, function() {
11.        
obj["e"+type+fn]();
12.      
} );
13.    
}
14.  
};
15.  
var onReady = function(loadEvent,waitForImages) {
16.    
if(waitForImages) {
17.      
return addEvent(window, 'load', loadEvent);
18.    
}
19.  
}
20.  
JS.onReady = onReady;
21.  
var $ = function(id){
22.    
return document.getElementById(id);
23.  
}
24.  
JS.$ = $;
25.})()<!doctype html>
<html dir="ltr" lang="zh-CN">
  <head>
   <meta charset="utf-8"/>
   <meta http-equiv="X-UA-Compatible" content="IE=Edge">
   <title>闭包环境中的事件加载</title>
   <script type="text/javascript">
  (function(){
   if(!window.JS){
     window['JS'] = {}
   }
   var addEvent = function( obj, type, fn ) {
     if (obj.addEventListener)
       obj.addEventListener( type, fn, false );
     else if (obj.attachEvent) {
       obj["e"+type+fn] = fn;
       obj.attachEvent( "on"+type, function() {
         obj["e"+type+fn]();
       } );
     }
   };
   var onReady = function(loadEvent,waitForImages) {
     if(waitForImages) {
       return addEvent(window, 'load', loadEvent);
     }
   }
   JS.onReady = onReady;
   var $ = function(id){
     return document.getElementById(id);
   }
   JS.$ = $;
})()

JS.onReady(function(){
   alert(JS.$("test").innerHTML)
},true);
JS.onReady(function(){
   alert("dddddddddddddddd")
},true);
   </script>
  </head>
  <body>
   <p id="test">Test</p>
  </body>
</html>
 
运行代码Javascript

OK,没问题。上面的onReady函数有一个可选参数,判断图片是否加载完毕。我们知道JS引擎会在完成DOM树后才开始处理图片与音频等东西,但如果我们的页面严重依赖于脚本布局呢?!我们想尽快让页面呈现出大体形态,这就用到domReady了。我们在原基础上改进它。

01.(function(){
02.  
if(!window.JS){
03.    
window['JS'] = {}
04.  
}
05.  
var addEvent = function( obj, type, fn ) {
06.    
if (obj.addEventListener)
07.      
obj.addEventListener( type, fn, false );
08.    
else if (obj.attachEvent) {
09.      
obj["e"+type+fn] = fn;
10.      
obj.attachEvent( "on"+type, function() {
11.        
obj["e"+type+fn]();
12.      
} );
13.    
}
14.  
};
15.  
var onReady = function(loadEvent,waitForImages) {
16.    
if(waitForImages) {
17.      
return addEvent(window, 'load', loadEvent);
18.    
}
19.    
var init = function() {
20.      
if (arguments.callee.done) return;
21.      
arguments.callee.done = true;
22.      
loadEvent.apply(document,arguments);
23.    
};
24.    
if(!+"\v1"){
25.      
(function(){
26.        
try {
27.          
document.documentElement.doScroll("left");
28.        
} catch(e) {
29.          
setTimeout( arguments.callee, 0 );
30.          
return;
31.        
}
32.        
init();
33.      
})();
34.    
}else{
35.      
document.addEventListener( "DOMContentLoaded", function(){
36.        
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
37.        
init();
38.      
}, false );
39.    
}
40.    
return true;
41.  
}
42.  
JS.onReady = onReady;
43.  
var $ = function(id){
44.    
return document.getElementById(id);
45.  
}
46.  
JS.$ = $;
47.})()
dom标准浏览器用DOMContentLoaded,这是非常正现的W3C论DOM方法,与FF的DOMMouseScroll 不一样,基本上所有非IE内核的浏览器最新版都支持它了。IE下我们可以通过侦听document. documentElement. doScroll()来判断DOM树是否完成,原理是IE下只有当DOM树构建完成后才能doScroll。但它还不是尽善尽美,它在IE下无法判定iframe的内容是否加载完毕。我们继续改进它。

01.(function(){
02.  
if(!window.JS){
03.    
window['JS'] = {}
04.  
}
05.  
var addEvent = function( obj, type, fn ) {
06.    
if (obj.addEventListener)
07.      
obj.addEventListener( type, fn, false );
08.    
else if (obj.attachEvent) {
09.      
obj["e"+type+fn] = fn;
10.      
obj.attachEvent( "on"+type, function() {
11.        
obj["e"+type+fn]();
12.      
} );
13.    
}
14.  
};
15.  
var onReady = function(loadEvent,waitForImages) {
16.    
if(waitForImages) {
17.      
return addEvent(window, 'load', loadEvent);
18.    
}
19.    
var init = function() {
20.      
if (arguments.callee.done) return;
21.      
arguments.callee.done = true;
22.      
loadEvent.apply(document,arguments);
23.    
};
24.    
if(!+"\v1"){
25.      
if(window.self == window.top){
26.        
(function(){
27.          
try {
28.            
document.documentElement.doScroll("left");
29.          
} catch(e) {
30.            
setTimeout( arguments.callee, 0 );
31.            
return;
32.          
}
33.          
init();
34.        
})();
35.      
}else{
36.        
document.attachEvent("onreadystatechange", function(){
37.          
if ( document.readyState === "complete" ) {
38.            
document.detachEvent( "onreadystatechange", arguments.callee );
39.            
init();
40.          
}
41.        
});
42.      
}
43.    
}else{
44.      
document.addEventListener( "DOMContentLoaded", function(){
45.        
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
46.        
init();
47.      
}, false );
48.    
}
49.    
return true;
50.  
}
51.  
JS.onReady = onReady;
52.  
var $ = function(id){
53.    
return document.getElementById(id);
54.  
}
55.  
JS.$ = $;
56.})()
我们简直是在重新实现jquery的$(document).ready(function(){ })!它功能非常强悍,配合利用闭包做成的命名空间,基本刀枪不入。而且它就只污染一个全局变量“JS”,可以与YUI媲美了(笑)。不过对于一般应用来说,我们用不着做到如此面面俱到。假如我们不需要对图片进行处理,页面也没有iframe,我们可以搞下面这个微缩版出来。

01.(function(){
02.  
if(!window.JS){
03.    
window['JS'] = {}
04.  
}
05.  
var onReady = function(loadEvent) {
06.    
if(!+"\v1"){
07.      
(function(){
08.        
try {
09.          
document.documentElement.doScroll("left");
10.        
} catch(e) {
11.          
setTimeout( arguments.callee, 0 );
12.          
return;
13.        
}
14.        
loadEvent();
15.      
})();
16.    
}else{
17.      
document.addEventListener( "DOMContentLoaded", loadEvent, false );
18.    
}
19.  
}
20.  
JS.onReady = onReady;
21.  
var $ = function(id){
22.    
return document.getElementById(id);
23.  
}
24.  
JS.$ = $;
25.})()<!doctype html>
<html dir="ltr" lang="zh-CN">
  <head>
   <meta charset="utf-8"/>
   <meta http-equiv="X-UA-Compatible" content="IE=Edge">
   <title>闭包环境中的事件加载</title>
   <script type="text/javascript">
 (function(){
   if(!window.JS){
     window['JS'] = {}
   }
   var onReady = function(loadEvent) {
     if(!+"\v1"){
       (function(){
         try {
           document.documentElement.doScroll("left");
         } catch(e) {
           setTimeout( arguments.callee, 0 );
           return;
         }
         loadEvent();
       })();
     }else{
       document.addEventListener( "DOMContentLoaded", loadEvent, false );
     }
   }
   JS.onReady = onReady;
   var $ = function(id){
     return document.getElementById(id);
   }
   JS.$ = $;
})()

JS.onReady(function(){
   alert(JS.$("test").innerHTML)
});
JS.onReady(function(){
   alert("dddddddddddddddd")
});
   </script>
  </head>
  <body>
   <p id="test">Test</p>
  </body>
</html>
 
运行代码

Tags:javascript 事件 加载

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接