javascript的事件加载

  • 来源: www.knowsky.com 作者: sevenleaf   2010-04-23/16:03
  •       通常来说,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>
          运行代码


    评论 {{userinfo.comments}}

    {{money}}

    {{question.question}}

    A {{question.A}}
    B {{question.B}}
    C {{question.C}}
    D {{question.D}}
    提交

    驱动号 更多