模拟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(DHTML)中的一些技巧
Jan 09 Javascript
jBox 2.3基于jquery的最新多功能对话框插件 常见使用问题解答
Nov 10 Javascript
javascript学习笔记(十二) RegExp类型介绍
Jun 20 Javascript
自己动手实现jQuery Callbacks完整功能代码详解
Nov 25 Javascript
jquery+ajax实现跨域请求的方法
Jan 20 Javascript
jQuery焦点控制图层展示延迟隐藏的方法
Mar 09 Javascript
JavaScript动态添加style节点的方法
Jun 09 Javascript
全面解析Bootstrap排版使用方法(文字样式)
Nov 30 Javascript
js表单元素checked、radio被选中的几种方法(详解)
Aug 22 Javascript
详谈js中window.location.search的用法和作用
Feb 13 Javascript
在Vue中使用icon 字体图标的方法
Jun 14 Javascript
彻底搞懂并解决vue-cli4中图片显示的问题实现
Aug 31 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 三维饼图的实现代码
2008/09/28 PHP
php中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
php判断ip黑名单程序代码实例
2014/02/24 PHP
PHP实现的文件操作类及文件下载功能示例
2016/12/24 PHP
JavaScript prototype 使用介绍
2013/08/29 Javascript
jquery.Ajax()方法调用Asp.Net后台的方法解析
2014/02/13 Javascript
JS使用getComputedStyle()方法获取CSS属性值
2014/04/23 Javascript
使用forever管理nodejs应用教程
2014/06/03 NodeJs
原生js模拟淘宝购物车项目实战
2015/11/18 Javascript
浅谈JavaScript对象的创建方式
2016/06/13 Javascript
jQuery获取所有父级元素及同级元素及子元素的方法(推荐)
2018/01/21 jQuery
VUE 3D轮播图封装实现方法
2018/07/03 Javascript
vue-cli 3.0 版本与3.0以下版本在搭建项目时的区别详解
2018/12/11 Javascript
动态内存分配导致影响Javascript性能的问题
2018/12/18 Javascript
vue父组件给子组件的组件传值provide inject的方法
2019/10/23 Javascript
微信小程序吸底区域适配iPhoneX的实现
2020/04/09 Javascript
微信小程序12行js代码自己写个滑块功能(推荐)
2020/07/15 Javascript
MySQL最常见的操作语句小结
2015/05/07 Python
Python编程实现从字典中提取子集的方法分析
2018/02/09 Python
python如何统计序列中元素
2020/07/31 Python
Python使用matplotlib模块绘制图像并设置标题与坐标轴等信息示例
2018/05/04 Python
详解Python 切片语法
2019/06/10 Python
django迁移数据库错误问题解决
2019/07/29 Python
django创建最简单HTML页面跳转方法
2019/08/16 Python
使用python实现男神女神颜值打分系统(推荐)
2019/10/31 Python
python getopt模块使用实例解析
2019/12/18 Python
Selenium 滚动页面至元素可见的方法
2020/03/18 Python
利用python批量爬取百度任意类别的图片的实现方法
2020/10/07 Python
猫途鹰英国网站:TripAdvisor英国(旅游社区和旅游评论)
2016/08/30 全球购物
No7 Beauty美国官网:英国国民护肤品牌
2019/10/31 全球购物
.NET初级开发工程师面试题
2014/04/18 面试题
奶茶专卖店创业计划书
2014/01/18 职场文书
打架检讨书300字
2014/02/02 职场文书
2014年五四青年节演讲稿范文
2014/04/22 职场文书
党政领导班子四风问题对照检查材料思想汇报
2014/10/02 职场文书
python opencv检测直线 cv2.HoughLinesP的实现
2021/06/18 Python