模拟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 相关文章推荐
使javascript也能包含文件
Oct 26 Javascript
Javascript load Page,load css,load js实现代码
Mar 31 Javascript
JavaScript 获取任一float型小数点后两位的小数
Jun 30 Javascript
用原生js做个简单的滑动效果的回到顶部
Oct 15 Javascript
深入浅析jQuery对象$.html
Aug 22 Javascript
详解基于webpack和vue.js搭建开发环境
Apr 05 Javascript
使用原生js写ajax实例(推荐)
May 31 Javascript
Easyui ueditor 整合解决不能编辑的问题(推荐)
Jun 25 Javascript
JS简单实现父子窗口传值功能示例【未使用iframe框架】
Sep 20 Javascript
详谈DOM简介及节点、属性、查找节点的方法
Nov 16 Javascript
利用Electron简单撸一个Markdown编辑器的方法
Jun 10 Javascript
jquery实现穿梭框功能
Jan 19 jQuery
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小程序自动提交到自助友情连接
2009/11/24 PHP
PHP 的比较运算与逻辑运算详解
2016/05/12 PHP
TFDN图片播放器 不错自动播放
2006/10/03 Javascript
真正的JQuery.ajax传递中文参数的解决方法
2011/05/28 Javascript
jquery 合并内容相同的单元格(示例代码)
2013/12/13 Javascript
jQuery学习笔记——jqGrid的使用记录(实现分页、搜索功能)
2016/11/09 Javascript
完全深入学习Bootstrap表单
2016/11/28 Javascript
js仿微信抢红包功能
2020/09/25 Javascript
JS实现延迟隐藏功能的方法(类似QQ头像鼠标放上展示信息)
2017/12/28 Javascript
详解webpack中的hash、chunkhash、contenthash区别
2018/01/05 Javascript
基于jquery trigger函数无法触发a标签的两种解决方法
2018/01/06 jQuery
浅谈Vue2.0中v-for迭代语法的变化(key、index)
2018/03/06 Javascript
VUE脚手架具体使用方法
2019/05/20 Javascript
百度小程序之间的页面通信过程详解
2019/07/18 Javascript
深入探索VueJS Scoped CSS 实现原理
2019/09/23 Javascript
深入分析jQuery.one() 函数
2020/06/03 jQuery
微信小程序多列表渲染数据开关互不影响的实现
2020/06/05 Javascript
vue项目中使用多选框的实例代码
2020/07/22 Javascript
浅谈JavaScript中this的指向更改
2020/07/28 Javascript
nuxt 自定义 auth 中间件实现令牌的持久化操作
2020/11/05 Javascript
vue实现动态表格提交参数动态生成控件的操作
2020/11/09 Javascript
python中的插值 scipy-interp的实现代码
2018/07/23 Python
Pandas DataFrame 取一行数据会得到Series的方法
2018/11/10 Python
HTML5学习笔记之html5与传统html区别
2016/01/06 HTML / CSS
Deichmann英国:德国鞋类零售商
2021/01/30 全球购物
一名毕业生的自我鉴定
2013/12/04 职场文书
总裁办公室主任职责
2014/01/02 职场文书
2014年迎新年联欢会活动策划方案
2014/02/26 职场文书
三好学生个人先进事迹材料
2014/05/17 职场文书
专升本学生毕业自我鉴定
2014/10/04 职场文书
党员个人查摆剖析材料
2014/10/16 职场文书
黄石寨导游词
2015/02/05 职场文书
2015年宣传思想工作总结
2015/05/22 职场文书
环保建议书作文400字
2015/09/14 职场文书
装修安全责任协议书
2016/03/22 职场文书
python中字符串String及其常见操作指南(方法、函数)
2022/04/06 Python