随着前端应用越来越火,应用越来越复杂,不管是什么系统,javascript开发很容易陷入混乱的状态,各种框架层出不穷,比如目前很火的jquery框架,虽然很是强大,但是在实际使用后,会发现很难完全支持业务的要求,如此扩展是一种很好的途径,然而,对很多人来说, 能完全应用已经很有难度,对其进行扩展完善,那就更难上加难了,在通过了多次的洗礼后,突然有种想要自己写控件框架的冲动,于是有了后续的这些文章。
为了简单起见,先创建如下目录结构。
+--demo
+--script
+--common
+--init.js
+--css
+--web
+--test.html
接着在common目录下添加init.js文件, 该文件,就是我们框架之源,负责加载js, css文件,先定义第一个对象scriptUtil;
复制代码 代码示例:
function scriptUtil() {
//加载导入的js列表
this.scriptList = {};
//加载的css列表
this.cssList = {};
//创建的控件类
this.com = {};
};
因为是第一个js文件,需要手工加载,在web目录下添加test.html文件,源码如下:
复制代码 代码示例:
<!DOCTYPE html>
<head><title>test</title>
<script src="../script/common/init.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
接下来,为了能够清楚加载的情况, 给对象scriptUtil添加一个日志输出的方法,其次添加一个加载成功的判断函数;
复制代码 代码示例:
scriptUtil.prototype = {
/**
* 日志输出.
* 参数 src 字符串
*/
LogInfo : function(src) {
if(window.console.info) {
window.console.info(src);
}
},
/**
* 是否加载判断.
* 参数 src 加载的文件名
*/
isImport : function(src) {
return (typeof this.scriptList[src] != "undefined"
|| typeof this.cssList[src] != "undefined");
}//方法之间用逗号隔开
}
加载的文件包含js、css两种格式, 因此需要添加一个文件类型判断函数
复制代码 代码示例:
scriptUtil.prototype = {
//之前添加过的方法
/**
* 文件类型.
* 参数 scr
文件路径
*/
scrType : function(scr) {
var scrAry = scr.split(".");
if (scrAry.length > 1) {
return scrAry[scrAry.length - 1].toUpperCase();
} else {
return "";
}
} //方法之间用逗号隔开,
}
因为使用的是普通的目录结构,因此需要处理相对路径的问题,添加一个获取根目录路径的函数(dome目录)。
说明,首先有两个路径, 一个是html文件的路径 即test.html的路径,另一个是js初始化文件的路径,即init.js的路径,通过这两个文件的路径,用来分析出整个工程的相对路径。
复制代码 代码示例:
scriptUtil.prototype = {
//之前添加过的方法
getPath : function() {
//获取默认的init.js文件路径
var srcUrl = document.getElementsByTagName("script")[0].src;
var re = /[/]+/g;
//判断是否是硬盘,或
服务器上的URL
if (/([a-zA-Z]:)|([hH][tT][tT][pP]://)/.test(srcUrl)) {
//获取html的URL
var docUrl = document.URL;
//拆分成数组
var srcAry = srcUrl.split(re);
var docAry = docUrl.split(re);
var indexs = 0;
//循环找到第一个不相同的目录
for ( var i = 0,
len = srcAry.length < docAry.length ? srcAry.length
: docAry.length;
i < len; i++) {
if (srcAry[i] !== docAry[i]) {
indexs = i;
break;
}
}
//test.html目录回寻到根目录
var path = "";
for ( var i = indexs, len = docAry.length; i < len - 1; i++) {
path = path + "../";
}
//完善js的目录
for ( var i = indexs, len = srcAry.length; i < len - 1; i++) {
path = path + srcAry[i] + "/";
}
return path;
} else {
//如果是相对目录,则直接使用。
var srcAry = srcUrl.split(re);
var path = "";
for ( var i = 0, len = srcAry.length; i < len - 1; i++) {
path = path + srcAry[i] + "/";
}
return path;
}
},
}
有了上面的准备, 接下来开始写这个类的核心函数,即import函数,这里重点讲一下,第一个参数, 可以传一个文件名, 也可以传一个数组, 是数组的情况下, 加载的文件,无论成功还是失败,都会在事件onload 或onerror里接着加载下一个文件,并在已加载列表中,打上标记。
复制代码 代码示例:
scriptUtil.prototype = {
//之前添加过的方法, 用逗号隔开
/**
* 加载文件,
* 参数 src 加载的文件,字符串或数组,
* 参数 callBack
回调函数,
* 参数 sPath 指定路径 默认为空
*/
Import : function(src, callBack, sPath) {
//路径
if(typeof sPath == "undefined") sPath = "";
//转换成数组
var src = src || [];
if(typeof src == "string") {
src = [src];
}
//获取head元素
var _doc = document.getElementsByTagName("head")[0];
var importObj = {};
if(src.length > 0) {
var curSrc = sPath + src[0];
//删除数组内第一个文件名
src.splice(0, 1);
var srctype = this.scrType(curSrc);
if(typeof this.scriptList[curSrc] === "undefined"
&& typeof this.cssList[curSrc] === "undefined") {
//如果没有加载过
if ("JS" == srctype) {
//加载js文件
importObj = document.createElement("script");
importObj.type = "text/javascript";
importObj.language = "javascript";
importObj.src = curSrc;
this.scriptList[curSrc] = 0;
} else if ("CSS" == srctype) {
//加载样式文件
importObj = document.createElement("link");
importObj.rel = "stylesheet";
importObj.type = "text/css";
importObj.href = curSrc;
this.cssList[curSrc] = 0;
}
//保存相关对象到importObj中
importObj.csrc = curSrc;
importObj.cstype = srctype;
importObj.self = this;
//加载成功事件
importObj.onload = importObj.onreadystatechange = function() {
var csrc = this.csrc;
if(!this.readyState||this.readyState=='loaded'
||this.readyState=='complete'){
var cst = this.cstype;
var Self = this.self;
//打上加载成功标志
if ("JS" == cst) {
Self.scriptList[csrc] = "sucess";
Self.LogInfo("import script " + csrc + " sucess.");
} else if ("CSS" == cst) {
Self.cssList[csrc] = "sucess";
Self.LogInfo("import css " + csrc + " sucess.");
}
this.onload=this.onreadystatechange=null;
//继续加载后续文件,
if(src.length > 0) {
Self.Import(src, callBack, sPath);
} else if(typeof callBack == "function") {
callBack(true);
}
this.self = null;
}
}
//导入错误的事件
importObj.onerror = function() {
var Self = this.self;
var csrc = this.csrc;
var cst = this.cstype;
//打上加载成功标志
if ("JS" == cst) {
Self.scriptList[csrc] = "error";
Self.LogInfo("import script " + csrc + " error.");
} else if ("CSS" == cst) {
Self.cssList[csrc] = "error";
Self.LogInfo("import css " + csrc + " error.");
}
//清除加载失败的文件
_doc.removeChild(importObj);
this.onerror = null;
//继续加载后续文件,
if(src.length > 0) {
Self.Import(src, callBack, sPath);
} else if(typeof callBack == "function") {
//回调
callBack(true);
}
this.self = null;
}
//添加加载文件到head中
_doc.appendChild(importObj);
} else {
if(src.length > 0) {
this.Import(src, callBack, sPath);
} else if(typeof callBack == "function") {
callBack(true);
}
}
} else if(typeof callBack == "function") {
callBack(true);
}
}// Import
}
到此, 一个完整的动态加载对象已编写完成。
请关注下一篇,将编写如何使用这个对象把更多的js导入到html页面中。