模拟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 相关文章推荐
巧妙破除网页右键禁用的十大绝招
Aug 12 Javascript
当前流行的JavaScript代码风格指南
Sep 10 Javascript
jquery实现顶部向右伸缩的导航区域代码
Sep 02 Javascript
如何防止JavaScript自动插入分号
Nov 05 Javascript
基于jQuery实现交互体验社会化分享代码附源码下载
Jan 04 Javascript
前端面试题及答案整理(二)
Aug 26 Javascript
JS高级运动实例分析
Dec 20 Javascript
jQuery实现简单的计时器功能实例分析
Aug 29 jQuery
Vue 中使用vue2-highcharts实现曲线数据展示的方法
Mar 05 Javascript
图文讲解用vue-cli脚手架创建vue项目步骤
Feb 12 Javascript
详解vue+axios给开发环境和生产环境配置不同的接口地址
Aug 16 Javascript
关于引入vue.js 文件的知识点总结
Jan 28 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
IIS php环境配置PHP5 MySQL5 ZendOptimizer phpmyadmin安装与配置
2008/11/18 PHP
php适配器模式介绍
2012/08/14 PHP
简单分析ucenter 会员同步登录通信原理
2014/08/25 PHP
php中Snoopy类用法实例
2015/06/19 PHP
php实现和c#一致的DES加密解密实例
2017/07/24 PHP
javascript学习笔记(四) Number 数字类型
2012/06/19 Javascript
jquery插件之信息弹出框showInfoDialog(成功/错误/警告/通知/背景遮罩)
2013/01/09 Javascript
有效提高JavaScript执行效率的几点知识
2015/01/31 Javascript
jquery.fastLiveFilter.js实现输入自动过滤的方法
2015/08/11 Javascript
JavaScript检测并限制复选框选中个数的方法
2015/08/12 Javascript
onclick和onblur冲突问题的快速解决方法
2016/04/28 Javascript
浅谈layer的iframe弹窗给里面的标签赋值的问题
2016/11/10 Javascript
BootStrap Table 设置height表头与内容无法对齐的问题
2016/12/28 Javascript
javascript回调函数的概念理解与用法分析
2017/05/27 Javascript
基于JavaScript实现弹幕特效
2020/08/27 Javascript
微信小程序methods中定义的方法互相调用的实例代码
2018/08/07 Javascript
Vue 开发音乐播放器之歌手页右侧快速入口功能
2018/08/08 Javascript
详解Vue CLI3 多页应用实践和源码设计
2018/08/30 Javascript
解决Vue在Tomcat8下部署页面不加载的问题
2019/11/12 Javascript
利用python实现xml与数据库读取转换的方法
2017/06/17 Python
Python中使用haystack实现django全文检索搜索引擎功能
2017/08/26 Python
Python编程二分法实现冒泡算法+快速排序代码示例
2018/01/15 Python
浅谈python中拼接路径os.path.join斜杠的问题
2018/10/23 Python
解决pyinstaller打包发布后的exe文件打开控制台闪退的问题
2019/06/21 Python
python实现关闭第三方窗口的方法
2019/06/28 Python
pytorch的batch normalize使用详解
2020/01/15 Python
python判断两个序列的成员是否一样的实例代码
2020/03/01 Python
如何基于线程池提升request模块效率
2020/04/18 Python
迪斯尼商品官方网站:ShopDisney
2016/08/01 全球购物
Vans澳大利亚官网:购买鞋子、服装及配件
2019/09/05 全球购物
写给爸爸的道歉信
2014/01/15 职场文书
教师工作能力自我评价
2015/03/04 职场文书
科技活动总结范文
2015/05/11 职场文书
故意杀人罪辩护词
2015/05/21 职场文书
关于python爬虫应用urllib库作用分析
2021/09/04 Python
MySQL图形化管理工具Navicat安装步骤
2021/12/04 MySQL