`
junjun16818
  • 浏览: 106235 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

手工打造Extjs (1) 类系统

阅读更多




最近看了几本javascrpt方面的书(javascript高级程序设计,javascript设计模式),内容中讲到很多面向对象式开发也提到很多优秀的javascript框架,
我很是费解为什么就没有提到过Extjs,难道YUI跟Extjs有那么大得深仇大恨?。


转入正题,我特别喜欢Extjs4 的类体系,所以就自己模仿的写了一个,我只是简单了解过extjs并没有深入去学习,所以有些地方可能不对还望大家指出。


在我的类体系中可以声明接口、抽象类、类,声明方式与extjs类似


下面是Extjs的类声明
Ext.define('Ext.panel.Panel', {
extend: 'Ext.panel.AbstractPanel'
// .....
})

下面是代码 :ClassManager.js


var Design = Design || {};


(function(Class) {
	/*先定义一些工具方法*/
	
	var widgetMap = {};
	
	var util = {
		/* 复制对象的属性,如果他们不存在 */
		applyIf: function(c1, c2) {
			if(typeof c1 == "object" && typeof c2 == "object"){
				for(var key in c2) {
					if(!c1[key]){
						c1[key] = c2[key];
					}
				}
			}
		},
		/* 复制对象的属性*/
		apply: function(c1, c2) {
			if(typeof c1 == "object" && typeof c2 == "object"){
				for(var key in c2) {
					c1[key] = c2[key];
				}
			}
			return c1;
		},
		isObject: function(o) {
			return (typeof o == "object");
		},
		isArray: function(o) {
			return (o instanceof Array);
		},
		isFunction: function(o) {
			return (typeof o == "function");
		},
		isString: function(o) {
			return (typeof o == "string");
		},
		isNumber: function(o) {
			return (typeof o == "number");
		},
		/*
			根据字符串类型获取一个类
		*/
		getClass: function(name) {
			if(typeof name !== "string")
				return name
		
			var v = name.split('.'),
				o = window[v[0]],
				i = 1,
				len = v.length;
			
			for(; i < len ; i++) {
				if(!o) return o
				o = o[v[i]] ;
			}
			return o;
		},
		/* 定义名字空间 */
		namespace: function(name) {
		
			if(typeof name !== "string")
				return name
		
			var v = name.split('.'),
				o = window[v[0]] = window[v[0]] || {},
				i = 1,
				len = v.length;
			
			for(; i < len ; i++) {
				o = o[v[i]] = o[v[i]] || {};
			}
			return o;
		},
		ns: function(){
			return this.namespace.apply(this,arguments);
		}
	}
	
	/*
		接口类  下面接口类是设计模式书中的一个例子 copy过来的
	*/
	
	var Interface = function(name, methods) {
		
		var i = 0,
			len = methods.length;
		
		this.name = name;
		this.methods = [];
		
		for (; i < len; i++) {
			this.methods.push(methods[i]);
		}
	}
	/*
		检测接口方法是否被实现
	*/
	Interface.ensureImplements = function(object) {
		
		var i = 1,
			len = arguments.length,
			j = 0,
			menthodsLen;
		for (; i < len; i++) {
			for (methodsLen = arguments[i].methods.length; j < methodsLen; j++) {
				var method = arguments[i].methods[j];
				if (!object[method] || typeof object[method] !== 'function') {
					throw new Error("类" + object.className + "未实现" + arguments[i].name + " 接口方法 " + method);
				}
			}
		}
	}
	
	/*
		类式继承
	*/
	function extend(subClass,superClass) {
		var F = function(){};
		F.prototype = superClass.prototype;
		subClass.prototype = new F();
		
		util.applyIf(subClass.prototype,new F())
		
		subClass.prototype.constructor = subClass;
		
		if (superClass.prototype.constructor == Object.prototype.constructor) {
			superClass.prototype.constructor = superClass;
		}
		/*
			为子类添加静态属性 superclass 指向父类
		*/
		subClass.superclass = superClass.prototype;
		/*
			为子类添加一个方法 callParent 调用父类的当前函数
		*/
		subClass.prototype.callParent = function(cfg) {
			var method,methodName;
			method = this.callParent.caller;
			for (var key in this) {
				if (this[key] === method) {
					methodName = key
				}
			}
			superClass.prototype[methodName].apply(this,cfg)
		}
		
	}
	
	/*
		添加别名到 widgetMap 对象中
	*/
	function setWidget(name,cls) {
		var n = name;
		if (name.indexOf('widget.') > -1) {
			n = name.substring(7,name.length);
		}
		widgetMap[n] = cls;
	}
	
	var pub = {
	
		/*
			使用字符串格式名称创建类
		*/
		create: function(name, cfg) {
			var clazz = util.getClass(name);
			return new clazz(cfg);
		},
		/*
			使用别名创建一个类
		*/
		widget: function(name, cfg) {
			var clazz = widgetMap[name];
			
			return new clazz(cfg);
		},
		/*
			声明一个类
		*/
		define: function(name ,cfg) {
			
			
			
			/*
				获取当前字符串name的变量
			*/
			var nameArr = ('window.'+name).split('.'),
				lastName = nameArr.pop(),
				beginName = nameArr.join('.'),
				thatClass = util.ns(beginName),
				parentClass = util.ns(cfg.extend),
				implement = cfg.implement;
				
			/*
				当前类型为接口时 创建接口并返回
			*/
			if (cfg.classType == "interface") {
				thatClass[lastName] = new Interface(name, cfg.methods);
				return;
			}
			
			/*
				创建对象 cfg.constructor 为构造函数
			*/
			if (cfg.constructor !== Object) {
				thatClass = thatClass[lastName] = cfg.constructor;
				delete cfg.constructor;
			}
			else {
				thatClass = thatClass[lastName] = function() {
					if (parentClass) {
						parentClass.prototype.constructor.apply(this,arguments)
					}
				};
			}
			
			/*
				当cfg里配置了父类时继承
			*/
			if (parentClass) {
				if (parentClass.prototype.events && cfg.events) {
					util.applyIf(cfg.events,parentClass.prototype.events);
				}
				extend(thatClass,parentClass);
			}
			util.apply(thatClass.prototype, cfg);
			thatClass.prototype.className = name;
			/*
				当配置了接口时,检查是否有没有实现的方法,如有没实现的方法将会抛出异常
			*/
			if (implement) {
				if (!util.isArray(implement)) {
					implement = [implement]
				}
				var i = 0,
					len = implement.length;
				
				for (; i < len; i++) {
					if (typeof implement[i] == 'string') {
						Interface.ensureImplements(thatClass.prototype,util.ns(implement[i]));
					}
					else if (typeof implement[i] == 'object') {
						Interface.ensureImplements(thatClass.prototype,implement[i]);
					}
					else {
						throw new Error("interface error implements type string and object");
					}
				}
				
			}
			/*
				当父类为抽象类时检测是否有为实现的方法
			*/
			if (parentClass && parentClass.classType == "abstract") {
			
				for (var i = 0, len = parentClass.methods.length; i < len; i++) {
					var method = parentClass.methods[i];
					if(!cfg[method] || typeof cfg[method] !== 'function'){
						throw new Error(name+" 未实现 "+ method +" 方法, 抽象类" + parentClass.className);
					}
				}
			
			}
			/*
				当前类为抽象类时添加几个静态属性 作为检测时使用
			*/
			if (cfg.classType == "abstract") {
				thatClass.classType = "abstract";
				thatClass.methods = cfg.methods;
			}
			/*
				当配置alias属性为当前类配置别名
				调用setWidget(name,class) 将别名与当前类添加到map中 
			*/
			if (cfg.alias) {
				if (util.isArray(cfg.alias)) {
					cfg.alias.forEach(
						function(it) {
							if (util.isString(it)) {
								setWidget(it, thatClass);
							}
							else {
								throw new Error("define argument 'alias' type Error");
							}
						}
					);
				}
				else if (util.isString(cfg.alias)) {
					setWidget(cfg.alias, thatClass);
				}
				else {
					throw new Error("define argument 'alias' type Error");
				}
			}
			
		}
	}
	
	util.applyIf(Class,pub);
	util.applyIf(Class,util);
})(Design);


html 页面

<script src = "ClassManager.js" ></script>


<script>
	
	Design.define('Design.interface.Component', {
		classType: 'interface',
		methods: ['initComponent', 'getItems']
	});
	
	Design.define('Design.panel.AbstractPanel', {
		classType: 'abstract',
		getElement: function() {
			return Document.createElement('div');
		},
		methods: ['getValue', 'setValue']
	});
	
	Design.define('Design.panel.Panel', {
		alias: 'panel', /*别名*/
		extend: 'Design.panel.AbstractPanel',  /* 继承抽象类 */
		implement: 'Design.interface.Component',  /* 继承接口 */
		constructor: function(cfg) { /*构造函数*/
			this.name = cfg.name;
		},
		getName: function() { /*类内方法*/
			return this.name;
		},
		initComponent: function(){ /* 必须实现的接口方法 没有这个方法将会抛出异常 */
		
		},
		getItems: function() { /* 必须实现的接口方法 没有这个方法将会抛出异常 */
		
		},
		getValue: function() { /* 必须实现的抽象方法 没有这个方法将会抛出异常 */
			
		},
		setValue: function() { /* 必须实现的抽象方法 没有这个方法将会抛出异常 */
			
		}
	});
	
	/* 创建Panel类 */
	var panel = new Design.panel.Panel({
		name: 'zwl'
	});
	
	/* 使用字符串类名创建 */
	panel = Design.create('Design.panel.Panel',{
		name: 'zwl'
	});
	
	/* 使用别名创建 */
	panel = Design.widget('panel',{
		name: 'zwl'
	});
	alert(panel.getName());
</script>



现在这个类系统已经完成  上面是一个测试的例子。现在还有一个问题,如果把Design.interface.Component 、 Design.panel.AbstractPanel Design.panel.Panel 分离出到js文件,
我们还需要在页面导入下面这几个文件.
<script src = "app/interface/Component.js" ></script>
<script src = "app/panel/AbstractPanel.js" ></script>
<script src = "app/panel/Panel.js" ></script>


如果类的数量一旦多起来,将要导入很多个js文件。这样的话 我的类系统太弱了,接下来添加一个动态导入js文件的功能


创建一个名叫Loader的js文件 代码如下

(function(Class) {
	/* 文件路径与转换名 */
	var path = {name: 'Design', replaceName: ''};
	/*  */
	var requireCount = 0;
	
	
	var addEvent = function(el,type, fn) {
		if (window.addEventListener){
			el.addEventListener(type, fn, false);
		}
		else if (window.attachEvent) {
			el.attachEvent('on' + type, fn);
		}
	}
	
	Class.onReady = function(callback) {
		
		addEvent(window, 'load', function(){
			/*每隔一段时间会判断是否还在加载类文件 在加载完成后调用回调*/
			var intervalId = setInterval(function(){
				if(requireCount === 0) {
					clearInterval(intervalId);
					callback();
				}
			},5)
		});
		
	};
	/* 导入类方法 */
	
	var require = function(urls, onLoad) {
		
		if (!Class.isArray(urls)) {
			urls = [urls];
		}
		
		var url,
			count = 0,
			i = 0,
			len = urls.length;
		
		for (; i < len; i++) {
			
			(function(i){
			
				count++ ;
				url = urls[i];
				requireCount++;
				if (url.indexOf(path.name) === 0) {
					url = path.replaceName + url.substring(path.name.length, url.length);
				}
				
				var script = document.createElement('script');
				script.type = 'text/javascript';
				script.src = url.replace(/\./g,'/')+'.js';
				script.onload = function() {
					count--;
					/*每隔一段时间会判断这个文件中得类是否已经声明完 如对象存在再调用回调*/
					var intervalId = setInterval(function(){
						if (Class.getClass(urls[i])) {
							requireCount--;
							clearInterval(intervalId);
							if (count == 0 && onLoad) {
								onLoad.call(window);
							}
						}
					},5)
				};
				script.onerror = function() {
					throw new Error(" require Errors url = " + url);
				};
				script.onreadystatechange = function() {
					if (this.readyState === 'loaded' || this.readyState === 'complete') {
					
					}
				};
				document.getElementsByTagName('head')[0].appendChild(script);
			
			})(i)
		
		}
		
	};
	
	var pub = {
	    /*设置路径*/
		setPath: function(o, n) {
			path.name = o;
			path.replaceName = n;
		}
	}
	Class.Loader = pub;
	Class.require = require;
})(Design);
 

最后在define方法最前面添加一段代码

var pub = {
	define: function(name ,cfg) {
		/*
			如果父类与接口不存在将阻止声明类
			先加载父类与接口加载完成后再声明类
		*/
		
		var requireList = [];
		
		if (cfg.extend && !util.getClass(cfg.extend)) {
			requireList.push(cfg.extend);
		}
		if (cfg.implement && !util.getClass(cfg.implement)) {
			requireList = requireList.concat(cfg.implement);
		}
		
		var loaderCount = requireList.length;
		for (var i = 0, len = requireList.length; i < len; i++) {
			Class.require(requireList[i], function() {	
				loaderCount--;
				if (loaderCount == 0) {
					pub.define(name, cfg);
				}
			});
		}
		
		if (requireList.length) {
			return;
		}
		
		//........
	}
}






html 页面

<script src = "ClassManager.js" ></script>
<script src = "Loader.js" ></script>


<script>
	Design.Loader.setPath('Design', 'apps');  // 配置路径 Design.panel.Panel 会转换成 apps/panel/Panel.js 既js文件的路径
	Design.require(['Design.panel.Panel']); // 在onReady之前会 加载3个js文件
	
	Design.onReady(function(){
		/* 使用别名创建 */
		panel = Design.widget('panel',{
			name: 'zwl'
		});
		alert(panel.getName());
		
	});
</script>

 

 

分享到:
评论

相关推荐

    extjs仿桌面系统

    在"EXTJS仿桌面系统"这个项目中,我们将探讨EXTJS如何实现类似桌面系统的功能和界面效果。 首先,EXTJS的组件库包含了各种各样的UI元素,如窗口(Window)、面板(Panel)、菜单(Menu)、按钮(Button)等,这些都...

    Extjs酒店管理系统

    《Extjs酒店管理系统详解》 在信息技术日新月异的时代,高效的管理软件是提升业务效率的关键。"Extjs酒店管理系统"就是这样一款集成了先进技术和强大功能的管理工具,专为酒店行业的运营而设计。该系统由Visual ...

    ExtJs教学管理系统

    "ExtJs教学管理系统"是一个基于ExtJs框架和.Net后端技术构建的应用程序,旨在提供一套教育机构或学校使用的教学管理解决方案。此系统可能包括学生管理、课程管理、成绩管理、教师管理等多个模块,以帮助教育工作者...

    ExtJS 物流管理系统源代码

    1. ExtJS:ExtJS是一个强大的JavaScript库,用于构建富互联网应用程序(RIA)。它提供了丰富的组件模型,包括表格、面板、表单、树等,可以创建复杂的用户界面。在物流管理系统中,ExtJS可能用于构建交互式的数据...

    jsp extjs Efs管理系统

    开发者可能会在这些文件中找到关于业务逻辑、数据访问对象(DAO)、控制器(Controller)以及与EXTJS前端交互的相关类。通过深入研究这些源码,可以学习到如何在JSP和EXTJS环境中实现完整的业务流程。 总的来说,...

    Extjs应用案例--<酒店管理系统>

    Extjs应用案例: 本酒店管理系统采用三层架构,SQL Server数据库。最主要的是采用了Extjs框架。 酒店系统实现了部分功能。aspx后台页面几乎无代码。业务逻辑处理全部采用Extjs自带的函数。对于学习Extjs的框架的...

    extjs的登录系统

    extjs的登录系统...............................

    EXTJS桌面系统-完整实例

    EXTJS桌面系统-完整实例 数据库可以根据映射文件自己简历 这里只是为大家展示一下

    ExtJs3 演示系统

    这个"ExtJs3演示系统"是一个基于ExtJs3版本的员工管理系统,它展示了如何利用该框架创建一个功能齐全、界面友好的应用。在这个系统中,你可以看到如何利用ExtJs3的组件库来构建各种用户界面元素,如表格、表单、树形...

    extjs得单页系统实例

    OPOAdemo.rar extjs得单页系统实例

    合同管理系统 extjs开发的 让大家一起学习

    总结,EXTJS为合同管理系统的开发带来了高效、灵活和丰富的用户界面,通过其强大的功能,可以打造出满足企业需求的合同管理平台,提升企业的合同管理效率和规范化程度。无论是前端界面设计还是后台数据交互,EXTJS都...

    EXTJS图书管理系统页面(JAVA)

    在"EXTJS图书管理系统页面(JAVA)"这个项目中,我们主要关注的是EXTJS在图书管理系统中的应用,以及它与Java后端的交互。 EXTJS提供了一套完整的组件库,包括表格、表单、面板、窗口、菜单等,使得开发者可以方便...

    Extjs文件管理系统

    ExtJS 文件管理系统是一款基于 ExtJS 框架构建的高效、功能丰富的文件管理应用程序。它提供了用户友好的界面,使得用户能够轻松地进行文件的压缩、解压以及搜索操作。ExtJS 是 Sencha 公司推出的一个强大的 ...

    基于ExtJS做的投票系统

    4. **响应式布局**:适应不同设备和屏幕尺寸的需要,ExtJS支持响应式布局,确保投票系统在桌面和移动设备上都能良好显示。 **投票系统关键模块** 1. **用户管理**:包括用户注册、登录、权限控制等功能,确保投票...

    Extjs版酒店管理系统

    总结,"Extjs版酒店管理系统"巧妙地结合了VS2005、SQL Server 2000和Extjs 2.0的优势,打造了一套功能齐全、操作便捷的管理工具。这种技术栈的运用,不仅提高了酒店运营效率,也为用户带来了现代、友好的交互体验。...

    extjs做的图书管理系统

    《基于ExtJS的图书管理系统详解》 图书管理系统是IT领域中的常见应用场景,它涉及到前端用户界面、后端数据处理以及数据库管理等多个技术层面。本文将详细介绍一个使用ExtJS开发的图书管理系统,该系统同时结合了...

    EXTJS 库存管理系统数据库脚本

    EXTJS 库存管理系统数据库脚本EXTJS 库存管理系统数据库脚本EXTJS 库存管理系统数据库脚本EXTJS 库存管理系统数据库脚本

    extjs4_任务调度管理系统

    本文将深入探讨如何利用EXTJS4开发任务调度管理系统,并结合SpringMVC、iBatis、Hibernate和Spring等技术进行后端整合,打造高效稳定的企业级应用。 首先,EXTJS4的核心在于其组件化的设计理念。在任务调度管理系统...

    extjs4_权限系统

    1. **权限系统erwin.bmp** - 这可能是用Erwin软件创建的实体关系图(ER图),用于描绘系统中各个实体(如用户、角色、权限等)之间的关系。ER图是数据库设计的重要工具,有助于理解和设计数据模型。 2. **经销商...

Global site tag (gtag.js) - Google Analytics