视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001 知道1 知道21 知道41 知道61 知道81 知道101 知道121 知道141 知道161 知道181 知道201 知道221 知道241 知道261 知道281
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
模拟jQuery中的ready方法及实现按需加载css,js实例代码_jquery
2020-11-27 21:14:08 责编:小采
文档

一、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('http://www.gxlcms.com/apps/tbtx/miiee/css/base.css', function(){
console.log('css加载完毕');
});
loadScript('http://www.gxlcms.com/apps/tbtx/miiee/js/jQuery.js', function(){
console.log('js加载完毕');
});
ready(function(){
console.log('dom is ready!');
});

下载本文
显示全文
专题