`
qinzhenzhou
  • 浏览: 10567 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

javascript控件开发之动态加载(1)

阅读更多
    做了几年开发, 平时看着会做框架的高手,那个羡慕妒忌恨呀,有闲的时候,总会想,要是自己能做一个框架该多好呀,经过一段时间的积累,有了一点点进步,于是决定亲手开发一个框架,本系列主要做一些初步的框架,希望自己学习,希望也能帮到跟我一样有梦想的人。
    所谓框架,就是基于它,能很方便的进行业务开发,减少技术上的时间花费,通过了解那么多框架后, 你是否也有想从0开始,自己开发一个呢!如果有,那就一起来吧,也许会有很大乐趣哦。
    此次要做的框架,是前端javascript框架,面向的是,大型应用前端界面,比如数据编辑,数据查询,数据管理等用到的前端控件及功能,有两个主要的目的, 第一, 简化web页面上的布局设计,第二,把应用尽可能的控件化,框架的开发思路是先做框架的布局,再开发具体的控件,接着扩展页面的控制,
    现在开始我们的控件框架之旅。   
先创建如下目录结构。
+--demo
     +--script
          +--common
               +--init.js
          +--css
     +--web
          +--test.html
以demo做为我们的框架的根目录,
script做为所有js的根目录,
script目录下的common目录作为框架基础目录,框架用到的文件都放置于此,css文件用于存放样式文件,
web则是页面目录,
整个框架中,需要一个起始js文件,这个文件将是我们框架的入口,起到初始化,加载,运行的作用,我们把文件命名为init.js并放在common目录下,
在init.js文件里定义第一个对象scriptUtil;该对象有三个属性,
    1. js脚本加载列表,
    2. css文件加载列表,
    3. 控件对象列表,
如下:
function scriptUtil() {
    //加载导入的js列表
    this.scriptList = {};
    //加载的css列表
    this.cssList = {};
    //创建的控件类
    this.com = {};
};

接着,编写一个页面test.html用于测试,并且引入init.js文件,放到web目录下
<!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");
    }//方法之间用逗号隔开
}

再添加一个文件类型判断函数,目前仅包括css, js两种文件
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的路径,通过这两个文件的路径,用来分析出整个工程的相对路径,
   1. 先判断是不是全路径,既http开头,或f:开头,
   2. 如果是,就从开始循环找到第一个不相同的目录,
   3. 通过html路径的相对深度,找到js文件,需要回退文件夹(../)的层次
   4. 拼成完成的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函数,函数需要三个参数,第一个参数, 可以传一个或多个文件名, 第二个参数,是回调函数,第三个是相对路径,因为路径不一定需要,因此放在第三个参数上,这里的实现算法是,
    1. 拿第一个文件,判断文件类型
    2. 生成对应的script或link对象,绑定onload和onerror事件
    3. 添加到<head>标签上,
    4. 在绑定的事件激活后,记录加载的文件,递归下一次调用,
    5. 如果加载完了,调用回调函数
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页面中。
分享到:
评论
4 楼 qinzhenzhou 2014-04-23  
onload, onerror 是<script>和<link>标签的两个事件,当执行
_doc.appendChild(importObj);
的时候,会开始加载,并激活这两个事件中的一个,成功就激活onload事件,失败就会激活onerror事件,
3 楼 nangonglingxue 2014-04-23  
这个onload事件跟onerror事件在什么时候用的??
2 楼 nangonglingxue 2014-04-23  
楼主, importObj.onload = importObj.onreadystatechange = function()
这里看不懂。。。
1 楼 网易YY 2014-04-17  
支持楼主,想跟楼主学习

相关推荐

    javascript控件开发之动态加载

    动态加载作为JavaScript控件开发中的一个重要概念,是提升网页性能和用户体验的关键手段。动态加载意味着控件或资源不是在页面加载时一次性全部加载,而是根据需要按需加载,从而减少了初始页面加载时间,降低了对...

    javascript控件开发之布局控件

    JavaScript控件开发是Web开发中的重要一环,特别是在构建交互丰富的网页应用时。布局控件是其中的关键元素,它允许开发者有效地组织和管理页面上的元素,实现多控件的协调和共存。在这个主题中,我们将深入探讨...

    javascript控件开发之工具栏控件

    在JavaScript控件开发中,工具栏控件是一个关键的元素,它通常被用来提供用户界面中的功能快捷方式或操作选项。工具栏控件的设计和实现是网页交互性的重要组成部分,尤其是在构建富客户端应用或者增强用户体验的网页...

    javascript控件开发之页面控制器

    在本主题"JavaScript控件开发之页面控制器"中,我们将深入探讨如何利用JavaScript来实现对网页的控制,特别是页面控制器的实现。页面控制器通常用于管理页面的导航、数据加载以及用户交互逻辑,它是构建大型单页应用...

    javascript控件

    JavaScript控件是网页开发中常用的一种元素,它们用于增强用户界面的交互性和功能。JavaScript是一种轻量级的脚本语言,常被嵌入HTML页面中,以实现动态内容的生成和用户交互。在这个主题中,我们将深入探讨...

    动态加载时间控件

    在网页开发中,动态加载时间控件是一种常见且实用的技术,它允许用户在页面交互过程中按需加载时间选择组件,从而提高页面性能和用户体验。这种技术尤其适用于数据量大或者资源消耗高的应用,因为它可以避免一次性...

    动态加载带参数的ASCX用户控件

    在.NET开发环境中,ASP.NET提供了一种强大的机制,允许开发者在运行时动态地加载和添加用户控件(ASCX)。这种技术在构建高度可配置、动态的Web应用程序时非常有用。"动态加载带参数的ASCX用户控件"是这个过程的一种...

    几个经典JavaScript控件

    在网页设计中,JavaScript控件是不可或缺的一部分,它们为用户提供了丰富的交互体验。以下是一些基于JavaScript的经典控件及其相关的知识点: 1. **表格操作**: - `javascript 表格操作.html` 和 `操控表格.txt` ...

    vue动态加载外部依赖js代码实现

    在前端开发中,有时我们需要动态地加载外部JavaScript库或脚本文件。特别是在构建大型Vue应用程序时,可能会遇到需要按需加载某些功能的情况,例如第三方库、API接口等。本文将详细介绍如何通过创建一个Vue组件来...

    asp.net动态加载JavaScript树

    ASP.NET动态加载JavaScript树是一种常见的前端交互技术,用于在网页中构建可扩展的、动态的树形结构。这种技术结合了后端ASP.NET的强大处理能力和前端JavaScript的灵活展示,为用户提供了良好的交互体验,尤其适用于...

    javascript调用ocx控件实现加载进度条

    在本例中,"javascript调用ocx控件实现加载进度条"意味着开发者已经创建了一个OCX(OLE Control Extension)控件,这是一个基于COM(Component Object Model)的二进制组件,专门用于在网页上显示和管理进度条。...

    Calendar日历JavaScript控件

    日历JavaScript控件在网页开发中广泛使用,主要功能是为用户提供直观的日期选择界面,增强用户体验。本文将深入探讨“Calendar日历JavaScript控件”的特点、使用方法及其实现原理。 首先,"Calendar日历JavaScript...

    c# webform 异步加载用户控件

    1. **创建用户控件**:首先,在项目中创建一个新的用户控件(ASCX文件),并在其中添加你需要的控件和逻辑。 2. **在主页面引用用户控件**:在需要异步加载的主页面中,为用户控件提供一个容器,例如一个空的Div,...

    VC++ Activex控件开发

    VC++ ActiveX控件开发是Windows应用程序开发中的一个重要部分,主要涉及的是利用Microsoft Visual C++这一集成开发环境(IDE)创建能够嵌入到其他应用程序、网页或者Active Desktop中的控件。ActiveX技术允许开发者...

    Web2.0控件开发

    Web2.0控件开发是.NET框架中一个关键的领域,它允许开发者创建高度交互、动态且用户友好的网页应用。在.NET环境中,控件是构建用户界面的基础元素,而Web2.0控件开发则进一步拓展了这些基础,引入了更先进的功能和...

    树控件,支持无限级树,支持动态加载节点。不用自己写js

    本项目提供了一个自定义的树控件,特别强调了其支持无限级节点以及动态加载功能,这意味着用户可以构建深度任意的树结构,并且在需要时按需加载子节点,从而提高应用程序的性能和用户体验。 首先,无限级树是树控件...

    JavaScript开发的日期控件

    JavaScript是一种广泛应用于网页和网络应用开发的脚本语言,它在客户端运行,为用户提供动态交互体验。在网页中,日期控件是常见的交互元素,用于选择或显示日期,常用于表单填写、事件安排等场景。这篇内容我们将...

    javascript树形控件

    1. DOM操作:JavaScript树形控件的基础是通过DOM(Document Object Model)来动态构建和操作页面元素。当用户点击节点时,JavaScript会修改DOM结构,展开或折叠相应的子节点。 2. 数据结构:树形控件的数据通常以...

    javascript 经典tab控件

    模仿ExtJS的Tab控件意味着它可能包含类似的功能,如动态添加和删除标签页、支持Ajax加载内容、自定义样式等。 在实际开发中,创建一个JavaScript Tab控件通常涉及以下几个关键步骤: 1. **HTML结构**:首先,我们...

Global site tag (gtag.js) - Google Analytics