模拟jQuery中的ready方法及实现按需加载css,js实例代码


  本文标签:jQuery,css,js

复制代码 代码如下:

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://www.jb51.net/apps/tbtx/miiee/css/base.css, function(){
    console.log(css加载完毕);
});
loadScript(http://www.jb51.net/apps/tbtx/miiee/js/jQuery.js, function(){
    console.log(js加载完毕);
});
ready(function(){
    console.log(dom is ready!);
});