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


Posted in Javascript onSeptember 27, 2013

一、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://3water.com/apps/tbtx/miiee/css/base.css', function(){
    console.log('css加载完毕');
});
loadScript('https://3water.com/apps/tbtx/miiee/js/jQuery.js', function(){
    console.log('js加载完毕');
});
ready(function(){
    console.log('dom is ready!');
});
Javascript 相关文章推荐
js技巧--转义符&quot;\&quot;的妙用
Jan 09 Javascript
实例:用 JavaScript 来操作字符串(一些字符串函数)
Feb 15 Javascript
理解Javascript_13_执行模型详解
Oct 20 Javascript
input 输入框获得/失去焦点时隐藏/显示文字(jquery版)
Apr 02 Javascript
纯Javascript实现Windows 8 Metro风格实现
Oct 15 Javascript
javascript中DOM复选框选择用法实例
May 14 Javascript
Three.js学习之几何形状
Aug 01 Javascript
jQuery实现简单的手风琴效果
Apr 17 jQuery
Vue利用History记录上一页面的数据方法实例
Nov 02 Javascript
浅析Vue.js 中的条件渲染指令
Nov 19 Javascript
jQuery事件模型默认行为执行顺序及trigger()与 triggerHandler()比较实例分析
Apr 30 jQuery
JavaScript使用setTimeout实现倒计时效果
Feb 19 Javascript
jquery ready函数、css函数及text()使用示例
Sep 27 #Javascript
javascript full screen 全屏显示页面元素的方法
Sep 27 #Javascript
实现动画效果核心方式的js代码
Sep 27 #Javascript
javascript中call和apply方法浅谈
Sep 27 #Javascript
文本框回车提交与禁止提交示例
Sep 27 #Javascript
JQuery事件e参数的方法preventDefault()取消默认行为
Sep 26 #Javascript
原生js实现改变随意改变div属性style的名称和值的结果
Sep 26 #Javascript
You might like
在WINDOWS中设置计划任务执行PHP文件的方法
2011/12/19 PHP
常见php数据文件缓存类汇总
2014/12/05 PHP
Zend Framework教程之路由功能Zend_Controller_Router详解
2016/03/07 PHP
javascript自启动函数的问题探讨
2013/10/05 Javascript
js函数返回多个返回值的示例代码
2013/11/05 Javascript
node.js中的http.response.addTrailers方法使用说明
2014/12/14 Javascript
JS实现登录页面记住密码和enter键登录方法推荐
2016/05/10 Javascript
扩展Bootstrap Tooltip插件使其可交互的方法
2016/11/07 Javascript
使用snowfall.jquery.js实现爱心满屏飞的效果
2017/01/05 Javascript
JS区分Object与Aarry的六种方法总结
2017/02/27 Javascript
BootstrapValidator实现注册校验和登录错误提示效果
2017/03/10 Javascript
vue.js指令v-model使用方法
2017/03/20 Javascript
jquery中封装函数传递当前元素的方法示例
2017/05/05 jQuery
JS事件流与事件处理程序实例分析
2019/08/16 Javascript
深入了解Vue3模板编译原理
2020/11/19 Vue.js
2款Python内存检测工具介绍和使用方法
2014/06/01 Python
python基础教程之匿名函数lambda
2017/01/17 Python
python 上下文管理器使用方法小结
2017/10/10 Python
使用python编写简单的小程序编译成exe跑在win10上
2018/01/15 Python
Django自定义用户认证示例详解
2018/03/14 Python
Python求解任意闭区间的所有素数
2018/06/10 Python
Python3+Appium安装使用教程
2019/07/05 Python
pandas.DataFrame的pivot()和unstack()实现行转列
2019/07/06 Python
Python递归函数 二分查找算法实现解析
2019/08/12 Python
python数据库编程 Mysql实现通讯录
2020/03/27 Python
Python 利用OpenCV给照片换底色的示例代码
2020/08/03 Python
Opencv python 图片生成视频的方法示例
2020/11/18 Python
删除pycharm鼠标右键快捷键打开项目的操作
2021/01/16 Python
HTML5离线缓存在tomcat下部署可实现图片flash等离线浏览
2012/12/13 HTML / CSS
德国家用电器购物网站:Premiumshop24
2019/08/22 全球购物
Tenstickers法国:墙贴和装饰贴纸
2019/08/26 全球购物
英国设计师珠宝网站:Joshua James Jewellery
2020/03/01 全球购物
酒店办公室文员岗位职责
2013/12/18 职场文书
党员公开承诺书和承诺事项
2014/03/25 职场文书
信电学院毕业生自荐书
2014/05/24 职场文书
财产保全担保书
2015/01/20 职场文书