日期:2014-05-16  浏览次数:20525 次

javascript控件开发之动态加载(1)
    随着前端应用越来越火,应用越来越复杂,不管是什么系统,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(console.info) {
            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 加载的文件,字符串或数