欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-11-08 14:11:46
一、ready函数的实现 经常用jquery类库或其他类库中的ready方法,有时候想想它们到底是怎么实现的,但是看了一下jquery中的,涉及到的模块比较多,(水平有限)代码比较难看懂;自己结合了...

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