模拟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 相关文章推荐
GWT中复制到剪贴板 js+flash实现复制 兼容性比较好
Mar 07 Javascript
关于IE浏览器以及Firefox下的javascript冒泡事件的响应层级
Oct 14 Javascript
FireFox下XML对象转化成字符串的解决方法
Dec 09 Javascript
向当前style sheet中插入一个新的style实现方法
Apr 01 Javascript
Jquery的Tabs内容轮换效果实现代码,几行搞定
Feb 12 Javascript
jquery退出each循环的写法
Feb 26 Javascript
avalonjs制作响应式瀑布流特效
May 06 Javascript
实践中学习AngularJS表单
Mar 21 Javascript
vue2实现移动端上传、预览、压缩图片解决拍照旋转问题
Apr 13 Javascript
vue实现一个炫酷的日历组件
Oct 08 Javascript
微信小程序 函数防抖 解决重复点击消耗性能问题实现代码
Sep 12 Javascript
js实现复制粘贴的两种方法
Dec 04 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
php中实现进程锁与多进程的方法
2016/09/18 PHP
解决laravel-admin 自己新建页面里 js 需要刷新一次的问题
2019/10/03 PHP
PHP与Web页面的交互示例详解二
2020/08/04 PHP
IE与Firefox下javascript getyear年份的兼容性写法
2007/12/20 Javascript
javascript 循环调用示例介绍
2013/11/20 Javascript
div浮层,滚动条移动,位置保持不变的4种方法汇总
2013/12/11 Javascript
JS网页图片按比例自适应缩放实现方法
2014/01/15 Javascript
原生js三级联动的简单实现代码
2016/06/07 Javascript
JS弹出新窗口被拦截的解决方法
2016/08/09 Javascript
jQuery动态追加页面数据以及事件委托详解
2017/05/06 jQuery
JavaScript贪吃蛇小组件实例代码
2017/08/20 Javascript
vue使用Element组件时v-for循环里的表单项验证方法
2018/06/28 Javascript
在Bootstrap开发框架中使用dataTable直接录入表格行数据的方法
2018/10/25 Javascript
使用JQuery自动完成插件Auto Complete详解
2019/06/18 jQuery
Element Cascader 级联选择器的使用示例
2020/07/27 Javascript
跟老齐学Python之深入变量和引用对象
2014/09/24 Python
简单介绍Python2.x版本中的cmp()方法的使用
2015/05/20 Python
Python基于pygame模块播放MP3的方法示例
2017/09/30 Python
浅谈Pandas中map, applymap and apply的区别
2018/04/10 Python
python sys.argv[]用法实例详解
2018/05/25 Python
使用python制作一个为hex文件增加版本号的脚本实例
2019/06/12 Python
django fernet fields字段加密实践详解
2019/08/12 Python
Python autoescape标签用法解析
2020/01/17 Python
如何通过python检查文件是否被占用
2020/12/18 Python
CSS3制作ajax loader icon实现思路及代码
2013/08/25 HTML / CSS
Html5中localStorage存储JSON数据并读取JSON数据的实现方法
2017/02/13 HTML / CSS
美国知名的旅游网站:OneTravel
2018/10/09 全球购物
美国最大的电子宠物训练产品制造商:PetSafe
2018/10/12 全球购物
eBay加拿大站:eBay.ca
2019/06/20 全球购物
c语言常见笔试题总结
2016/09/05 面试题
材料加工工程求职信
2014/02/19 职场文书
入股协议书范本
2014/04/14 职场文书
创业融资计划书
2014/04/25 职场文书
资源环境与城乡规划管理专业自荐书
2014/09/26 职场文书
房屋登记授权委托书范本
2014/10/09 职场文书
英雄儿女观后感
2015/06/09 职场文书