zoukankan      html  css  js  c++  java
  • jQuery中的ready方法及实现按需加载css,js

    一、ready函数的实现

    经常用jQuery类库或其他类库中的ready方法,有时候想想它们到底是怎么实现的,但是看了一下jQuery中的源码,涉及到的模块比较多,(水平有限)代码比较难看懂;自己结合了一些书籍内容,总结一下。

    先说一下ready函数的实现思路:

    变量ready通过表达式赋值,右侧为一个自执行匿名函数,在这个匿名函数中,首先为各个浏览器的事件绑定处理函数,并为isReady赋值(根据事件异步处理程序来确定),然后返回一个传参闭包,在闭包中,主要判断isReady值来执行操作,如果dom结构准备就绪(isReady === true),执行回调,否则将回调加入到要执行的队列(funs)中,待事件处理程序执行时,循环遍历队列(funs),并依次执行队列中的函数,执行完队列中的函数后,还需要清除队列(funs = null)。

    复制代码
    var ready = (function(){
        var isReady = false,
        funs = [];
    
        function handle (e) {
            if ( isReady ) {
                return;
            }
            if ( e.type === 'readystatechange' && (document.readyState !== 'interactive' && document.readyState !== 'complete') ) {
                return;
            }
    
            for ( var i = 0; i < funs.length; i++ ) {
                funs[i].call(document);
            }
            isReady = true;
            funs = null;
        }
    
        if ( document.addEventListener ) {
            document.addEventListener( 'DOMContentLoaded', handle, false );
            document.addEventListener( 'readystatechange', handle, false );
            document.addEventListener( 'load', handle, false );
        }
        else if ( document.attachEvent ) {
            document.attachEvent( 'onreadystatechange', handle );
            document.attachEvent( 'onload', handle );
        }
    
        return function ready (callback) {
            if ( isReady ) {
                callback.call(document);
            }
            else {
                funs.push(callback);
            }
        };
    }());
    复制代码

    PS:

    该函数代码参照于权威指南书籍,唯一不同的是,多加了一个判断document.readyState !== 'interactive'

    if ( e.type === 'readystatechange' && (document.readyState !== 'interactive' && document.readyState !== 'complete') ) {
        return;
    }

    在各个浏览器中交互和完成状态出现顺序并不能保证一致,这取决于浏览器及页面的内容,多加了这个判断document.readyState !== 'interactive'的话,
    意思是不管哪个阶段先出现,代码都能更早的执行。

    二、按需加载css,js

    参照了jQuery源码,写了一个type函数,返回参数类型。 

    复制代码
    /**
     *
     * 判断参数类型
     * createTime: 2013/9/18
     *
     */
    
    function type (obj) {
        var classTypes, objectTypes;
    
        if ( obj == null ) {
            return String(obj);
        }
    
        classTypes = {};
        objectTypes = ('Boolean Number String Function Array Date RegExp Object Error').split(' ');
        
        for ( var i = 0, len = objectTypes.length; i < len; i++ ) {
            classTypes[ '[object ' + objectTypes[i] + ']' ] = objectTypes[i].toLowerCase();
        }
    
        if ( typeof obj === 'object' || typeof obj === 'function' ) {
            var key = Object.prototype.toString.call(obj);
            return classTypes[key];
        }
        return typeof obj;
    }
    复制代码
    复制代码
    // css按需加载
    function loadCss (cssUrl, callback) {
        var elem, bl,
            isExecuted = false; // 防止在ie9中,callback执行两次
        
        if ( cssUrl == null ) {
            return String(cssUrl);
        }
        elem = document.createElement('link'),
        elem.rel = 'stylesheet';
        if ( type(callback) === 'function' )  {
            bl = true;
        }
    
        // for ie
        function handle() {
            if ( elem.readyState === 'loaded' || elem.readyState === 'complete' ) {
                if (bl && !isExecuted) {
                    callback();
                    isExecuted = true;
                }
                elem.onreadystatechange = null;
            }
        }
        elem.onreadystatechange = handle;
    
        // for 非ie
        if (bl && !isExecuted) {
            elem.onload = callback;
            isExecuted = true;
        }
    
        elem.href = cssUrl;
        document.getElementsByTagName('head')[0].appendChild(elem);
    }
    
    // js按需加载
    function loadScript(scriptUrl, callback) {
        var elem, bl,
            isExecuted = false; // 防止在ie9中,callback执行两次
    
        if (scriptUrl == null) {
            return String(fn);
        }
        elem = document.createElement('script');
        if ( type(callback) === 'function' )  {
            bl = true;
        }
    
        // for ie
        function handle(){
            var status = elem.readyState;
            if (status === 'loaded' || status === 'complete') {
                if (bl && !isExecuted) {
                    callback();
                    isExecuted = true;
                }
                elem.onreadystatechange = null;
            }
        }
        elem.onreadystatechange = handle;
    
        // for 非ie
        if (bl && !isExecuted) {
            elem.onload = callback;
            isExecuted = true;
        }
    
        elem.src = scriptUrl;
        document.getElementsByTagName('head')[0].appendChild(elem);
    }
    复制代码

    PS: 在判断link,script元素是否加载完毕,主要依靠load事件;而在ie9以下浏览器中,并没有load事件,ie为它们都添加了一个readystatechange事件,通过判断
    元素的readyState状态确定元素是否已经加载完毕;而奇怪的是,在ie9(还可能存在其他浏览器版本)中,元素既有load事件又有readystatechange事件,因此在代码中添加了一个变量isExecuted,如果执行过回调,那么就不再执行,避免回调执行两次。

    三、调用方式

    复制代码
    loadCss('http://a.tbcdn.cn/apps/tbtx/miiee/css/base.css', function(){
        console.log('css加载完毕');
    });
    
    loadScript('http://a.tbcdn.cn/apps/tbtx/miiee/js/jQuery.js', function(){
        console.log('js加载完毕');
    });
    
    ready(function(){
        console.log('dom is ready!');
    });
    复制代码
     
     
    分类: JavaScript
  • 相关阅读:
    (转)nginx的root和alias指令的区别
    (转)Bash 快捷键 完整版
    (转)curl 命令使用
    Ansible 部署
    (转)把Sublime Text 2 加入右键菜单(带图标),Edit with Sublime Text
    配置IP地址及HOSTNAME脚本
    Linux Shell : Test命令参数解析
    计算阶乘 n! = 1 * 2 * 3 * ... * n
    .编写一个函数,输入n为偶数时,调用函数求1/2+】1/4+...+1/n,当输入n为奇数时,调用函数1/1+1/3+...+1/n
    简单的ATM机的取款过程
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3329401.html
Copyright © 2011-2022 走看看