从TUI.panel依赖想到的,panel的文件都在全局里面,每次修改都需上全局,修改测试起来都太麻烦。
TUI.use也只是单文件依赖加载,没有多文件也没有css依赖加载。
另一种角度考虑panel使用,将css和js分别都提取出来为单独的文件,在需要使用的时候,先mask掉page,然后异步加载这两个文件,完成后callback执行。
小知识:土豆前端静态文件版本管理系统很完善,每个静态文件发布时会在文件名(不包含扩展名)后自动增加_数字,这使得历史记录查询对比以及回退成为了可能。在需要异步加载所依赖的文件时,需要用use取得带版本号的完整url才可。
伪代码:
var module = {}, //模块库,用以类似YUI.use异步加载css或js模块
modules = {}, //多个模块同时加载时记录的callback
TUI.mix({
/**
* @public 字符串是否以指定sub结尾
* @param {string} str需要确定的字符串
* @return {string} 结尾
*/
endWith: function(str, sub){
return str.lastIndexOf(sub) == str.length - sub.length;
},
/**
* @public 注册单个模块文件方法
* @param {string} js的url
* @param {boolean} 是否延迟加载,即是在use调用的时候加载还是domready时加载
*/
join: function(url, noLazy) {
var res = /(.+)_\d+\.(js|css)/.exec(url),
key = res[1] + '.' + res[2],
mod = module[key] || {};
mod.name = key;
mod.url = url;
mod.cb = [];
module[key] = mod;
//若指定第2个参数为true,则立刻加载,否则use时加载
if(noLazy) {
this.use(key);
}
},
/**
* @public 注册多个模块文件方法
* @param {array} 模块列表
* @param {boolean} 是否延迟加载,即是在use调用的时候加载还是domready时加载
*/
joins: function(list, noLazy) {
var that = this;
list.forEach(function(item) {
that.join(item, noLazy);
});
},
/**
* @public 异步使用单个css或js文件方法,
* @param {string} 文件的url不带版本号
* @param {function} 加载成功后的调用函数
*/
use: function(key, cb) {
var mod = module[key],
that = this;
//必须先join注册
if(!mod) {
return;
}
if($.isFunction(cb)) {
mod.cb.push(cb);
}
//尚未加载成功时
if(!mod.loaded && !mod.loading) {
mod.loading = true;
$(function() {
if(that.endWith(key, '.js')) {
that.getScript(mod.url, {
charset: mod.charset,
callback: function(){
mod.loaded = true;
mod.cb.forEach(function(cb) {
cb();
});
}
});
}
else if(that.endWith(key, '.css')) {
that.getCss(mod.url, function() {
mod.loaded = true;
mod.cb.forEach(function(cb) {
cb();
});
});
}
module[key] = mod;
});
}
//已经加载完成了这个js文件,直接执行cb
else if($.isFunction(cb)) {
cb();
}
},
/**
* @public 异步使用多个css或js文件方法,
* @param {array} url列表
* @param {function} 加载成功后的调用函数
*/
uses: function(keys, cb) {
//所有mod必须先join注册
for(var i = keys.length - 1; i > -1; i--) {
if(!module[keys[i]]) {
return;
}
}
var k = keys.join(''),
mods = modules[k] || [],
that = this;
if($.isFunction(cb)) {
mods.push(cb);
}
modules[k] = mods;
keys.forEach(function(mod) {
that.use(mod);
});
//定时侦听所有模块,全部加载完成后执行cb列表
var interval = setInterval(function() {
var fin = true;
keys.forEach(function(mod) {
if(!module[mod].loaded) {
fin = false;
return fin;
}
});
if(fin) {
mods.forEach(function(item) {
item();
});
clearInterval(interval);
}
}, 50);
},
/**
* @public 异步加载js文件方法
* @param {string} js的url
* @param {object} 选项传入charset和callback
*/
getScript: function(url, op) {
var s = this.create('script'),
head = this.tag('head')[0],
done = false;
s.type = "text/javascript";
s.async = true; //for firefox3.6
if($.isFunction(op)) {
op = { callback: op };
}
op = op || {};
if(op.charset) {
s.charset = op.charset;
}
s.src = url;
s.onload = s.onreadystatechange = function(){
if (!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
done = true;
//防止ie内存泄漏
s.onload = s.onreadystatechange = null;
head.removeChild(s);
if(op.callback) {
op.callback();
}
}
};
head.appendChild(s);
},
/**
* @public 异步加载css文件方法
* @param {string} css的url
* @param {function} callback
*/
getCss: function(url, cb) {
var that = this;
$.ajax({
url: url,
success: function(data) {
var s = that.create('style'),
head = that.tag('head')[0];
s.type = 'text/css';
//ie和其它要分开对待
if(s.styleSheet) {
s.styleSheet.cssText = data;
}
else {
s.appendChild(document.createTextNode(data));
}
head.appendChild(s);
if(cb) {
cb();
}
}
});
}
});
实际使用时,是这样:
//这会在模板上jion
TUI.joins(['out_1.css', 'out_1.js']);
//真正执行
TUI.uses(['out.css', 'out.js'], function() {
alert(1);
});


本博客所有文章均采用