读Ext消息机制有感之简单仿写(二)

之前在  读Ext消息机制有感之简单仿写(一)中仿写了一部分的Ext事件机制内容。Ext中还有一个重要的类Ext.Observable,这里只要继承这个类,我们继承后的类也可以将加入自己的事件响应函数。然后根据(一)中介绍的内容,结合起来处理html中的一些原生的事件。在这篇学习笔记的封装代码中实现对一个事件响应多个函数的情况

下面的代码是看了Ext相关源码进行编写为的是提升自身js水平,忽略了不少东西,对一些响应函数的作用域以及返回的参数也处理的不是很好。仅供参考微笑

Ext.Observable = function() {
	var scope = this;
	if(scope.addListeners) { //存在addListeners对象,就执行addListeners方法
		scope.addListener(scope.addListeners);
	}
	scope.events = scope.events || {};
}

Ext.apply(Ext.Observable,{
	addListener: function(ename, fn, scope) {  //第一个参数可能是对象listeners: {'click': function(){}} 也可能是事件名字
		if(Ext.isObject(ename)) {
			for(var key in ename) {
				var fn = ename[key];
				this.addListener(key,fn,ename.scope || fn.scope); //提供一个作用用,在使用者编写消息响应函数的时候,通过调用this使用
			}
		}else {
			if(typeof ename == 'string') {
				var event = this.events[ename] || true;  //this.addEvents执行在前,创建了events数组,或者在调用构造函数Observable时执行scope.events = scope.events || {};在后面通过创建的对象调用addEvents 和addListeners
				if(typeof event == 'boolean') {   //如果是boolean类型,说明这这个ename里面没有响应函数
					this.events[ename] = new Ext.Event(this, ename);   //这里的this其实就是继承Observable的自定义组件
				}
				this.events[ename].addListener(fn, scope); 
			}
		}
	},
	fireEvent: function() {
		//这里简单化,忽略冒泡等
		var arg = Ext.toArray(arguments);
		var ename = arg[0].toLowerCase();
		var flag = false;
		var event = this.events[ename];  //如果之前addEvent && addListener则存在 返回Event对象
		if(Ext.isObject(event)) {
			if(event.fire.call(event,arg.slice(1)) === false) {  //第一个参数,让fire方法里面的this还是属于event,不然,如果是别的对象,fire里面this的属性会复制给这个对象
				return false;
			}
			flag = true;
		}
		return flag;
	},
	addEvent: function() {
		var arg = arguments[0];
		this.events = this.events || {};  //this.events如果不存在就直接创建一个空对象,这里events可能在这里创建,也可能在Observable构造函数中创建
		if(typeof arg == 'string') {
			var len = arguments.length;
			while(len--) {
				var ename = arguments[len];
				this.events[ename] = this.events[ename] || true;  //如果ename不存在就创建,存在就覆盖,这里覆盖成原来的值
			}	
		}
	}
})

Ext.Event = function(scope, ename) {
	this.ename = ename;
	this.scope = scope;
	this.listeners = [];
}

Ext.apply(Ext.Event, {
	addListener: function(fn, scope) {
		scope = scope || this.scope;
		//先判断这个fn在这个scope作用域是否存在,如果在调用addListener或者addListener定义的对象
		//中没有指明scope作用域,那么默认是以这个组件为响应函数的作用域
		if(!this.isExistListener(fn, scope)) {   //如果已经有这个响应函数就不需要重复放到listeners数组里面了
			var listener = this.createListener(fn, scope);
			if(this.fireing) {  //这个事件已经在执行其中的响应函数
				this.listeners = Array.prototype.slice.call(this.listeners, 0);
			}
			this.listeners.push(listener); //将这个事件的其中之一的响应函数放到listener数组中
		}
	},
	isExistListener: function(fn, scope) {
		var len = this.listeners.length;
		while(len--) {
			if(listeners[len].fn == fn && listeners[len].scope == scope) {
				return true;
			}
		}
		return false;
	},
	createListener: function(fn, scope) {
		var obj = {
			fn: fn,
			scope: scope
		}
		obj.fireFn = fn;   //这里先忽略target、delay、single、buffer的处理
		return obj;
	},
	fire: function() {
		var option = Ext.toArray(arguments);
		var len = this.listeners.length;
		while(len--) {
			this.fireing = true; //表示已经是执行状态了
			var fn = this.listeners[len];
			if(fn.fireFn.apply(fn.scope || this.scope, option) === false) {   //第一个参数是给响应函数指明作用域如果fn.scope不存在就使用这个Event(click)的scope
				return (this.fireing = false);   //执行结束
			}
		}
		this.fireing = false; //如果listeners都执行完,就让this.fireing变成false
		return true;
	}
});

Ext.toArray = function(arg) {
	var agent = navigator.userAgent.toLowerCase();
	if(!(/opera/.test(agent)) && /msie/.test(agent)) {  //IE浏览器,不能使用Array.prototype.slice.call(arg,0);
		var array = [];
		for(var index = 0; index < arg.length; index++) {
			array[index] = arg[index];
		}
		return array;
	}else { //其他浏览器
		return Array.prototype.slice.call(arg,0);
	}
}

Ext.extend = function(target, source, obj) {
	if(Ext.isObject(source)) {
		obj = source;
		source = target;
		target = obj.constructor? obj.constructor : function() {
			source.apply(this,arguments);						
		}
	}
	var fn = function() {};
	fn.prototype = source.prototype;;
	target.prototype = new fn();
	target.prototype.constructor = target;
	target.prototype.superclass = source.prototype;
	for(var key in obj) {
		target.prototype[key] = obj[key];
	}
	target.extend = function(source, obj) {    //给这个继承的组件提供一个extend方法
		Ext.extend(target,source,obj);
	}
	target.superclass = function() {          //定义一个返回superclass的方法
		return source.prototype; 
	}
	return target;
}

Ext.MyEvent = function() {
	this.name = 'stray';
	this.time = '2015-4-27';
	this.addEvent('show','read');
	Ext.MyEvent.prototype.superclass.constructor.call(this,arguments); //这一句代码挺关键的,主要是执行Ext.Observable构造函数
};
Ext.extend(Ext.MyEvent, Ext.Observable, {
	addListeners: {
		show: function() {
			alert('由'+ this.name + '在' + this.time + '提供');  //这里为什么可以使用this? 上边fire函数中已经指明了作用域scope
		},
		read: function() {
			alert('正在操作read响应函数');		
		}
	}
});


下面附上完整的代码

<%@ page contentType="text/html; charset=UTF-8" %>
<html>
<head>
<script type="text/javascript"><!--
Ext = {version: '1.1'};
Ext.cacheEl = {};
/**
	@param element: 原生element元素 或者是String类型的id
	如果是new function创建的对象或者{}类型的,都是返回ture
*/
Ext.isObject = function(obj) {
	return Object.prototype.toString.call(obj) == '[object Object]'? true : false;
}
/**
	@param source 源
	@param target 目标,这里的数据拷贝到source的prototype上
	target可以是fucntion 创建的对象,也可以是{}类型
*/
Ext.apply = function(source,target) {
	var _proto = source.prototype;
	if(Ext.isObject(target)) {
		for(var el in target) {
			_proto[el] = target[el]; 
		}
	}
	return source;
}
Ext.Element = function(element) {   
	element = typeof element == 'string'? document.getElementById(element) : element;
	if(!element) {
		return null;
	}
	var idEl = element.id;
	if(idEl && !Ext.cacheEl[idEl]) {
		Ext.Element.toAddCache(element);
	}
	this.dom = element;
	this.id = idEl;
}
Ext.Manager = function() {
	//定义其他方法供返回对象里面的方法调用
	return {
		addLister: function(event,actor,scope) {
			var dom = Ext.cacheEl[scope.id].el; //这里其实可以直接用scope.dom或者由上边个参数进来,为了使用Ext.cacheEl,所以这么写
			if(window.addEventListener) {
				dom.addEventListener(event, actor);
			}else{
				if(window.attachEvent) {
					dom.attachEvent('on' + event, actor);
				}
			}
		}
	};
}();
Ext.apply(Ext.Element,{
	addListener: function(event,fn) {  //addListener('click',function(){})
		var scope = this;
		var idEl = scope.id;
		var eventEl = Ext.cacheEl[idEl].events;
		eventEl[event] = [fn];
		function actor(event) {
			//这里Ext可以将event封装成自身的消息对象
			fn.apply(fn.scope || {});        //执行相应函数,在这里可以定义一些参数,供使用者在编写相应方法时候调用
		}
		Ext.Manager.addLister(event,actor,scope);
	}
});

/**
	@param element: 原生element元素
*/
Ext.Element.toAddCache = function(element) {
	var obj = {
		el: element,
		data: [],
		events: []
	}
	Ext.cacheEl[element.id] = obj;
}
/**
	定义几个将原生dom封装成Ext自定义的Element元素
*/
Ext.get = Ext.find = function(element) {
	element = new Ext.Element(element);
	return element;
}


Ext.Observable = function() {
	var scope = this;
	if(scope.addListeners) { //存在addListeners对象,就执行addListeners方法
		scope.addListener(scope.addListeners);
	}
	scope.events = scope.events || {};
}

Ext.apply(Ext.Observable,{
	addListener: function(ename, fn, scope) {  //第一个参数可能是对象listeners: {'click': function(){}} 也可能是事件名字
		if(Ext.isObject(ename)) {
			for(var key in ename) {
				var fn = ename[key];
				this.addListener(key,fn,ename.scope || fn.scope); //提供一个作用用,在使用者编写消息响应函数的时候,通过调用this使用
			}
		}else {
			if(typeof ename == 'string') {
				var event = this.events[ename] || true;  //this.addEvents执行在前,创建了events数组,或者在调用构造函数Observable时执行scope.events = scope.events || {};在后面通过创建的对象调用addEvents 和addListeners
				if(typeof event == 'boolean') {   //如果是boolean类型,说明这这个ename里面没有响应函数
					this.events[ename] = new Ext.Event(this, ename);   //这里的this其实就是继承Observable的自定义组件
				}
				this.events[ename].addListener(fn, scope); 
			}
		}
	},
	fireEvent: function() {
		//这里简单化,忽略冒泡等
		var arg = Ext.toArray(arguments);
		var ename = arg[0].toLowerCase();
		var flag = false;
		var event = this.events[ename];  //如果之前addEvent && addListener则存在 返回Event对象
		if(Ext.isObject(event)) {
			if(event.fire.call(event,arg.slice(1)) === false) {  //第一个参数,让fire方法里面的this还是属于event,不然,如果是别的对象,fire里面this的属性会复制给这个对象
				return false;
			}
			flag = true;
		}
		return flag;
	},
	addEvent: function() {
		var arg = arguments[0];
		this.events = this.events || {};  //this.events如果不存在就直接创建一个空对象,这里events可能在这里创建,也可能在Observable构造函数中创建
		if(typeof arg == 'string') {
			var len = arguments.length;
			while(len--) {
				var ename = arguments[len];
				this.events[ename] = this.events[ename] || true;  //如果ename不存在就创建,存在就覆盖,这里覆盖成原来的值
			}	
		}
	}
})

Ext.Event = function(scope, ename) {
	this.ename = ename;
	this.scope = scope;
	this.listeners = [];
}

Ext.apply(Ext.Event, {
	addListener: function(fn, scope) {
		scope = scope || this.scope;
		//先判断这个fn在这个scope作用域是否存在,如果在调用addListener或者addListener定义的对象
		//中没有指明scope作用域,那么默认是以这个组件为响应函数的作用域
		if(!this.isExistListener(fn, scope)) {   //如果已经有这个响应函数就不需要重复放到listeners数组里面了
			var listener = this.createListener(fn, scope);
			if(this.fireing) {  //这个事件已经在执行其中的响应函数
				this.listeners = Array.prototype.slice.call(this.listeners, 0);
			}
			this.listeners.push(listener); //将这个事件的其中之一的响应函数放到listener数组中
		}
	},
	isExistListener: function(fn, scope) {
		var len = this.listeners.length;
		while(len--) {
			if(listeners[len].fn == fn && listeners[len].scope == scope) {
				return true;
			}
		}
		return false;
	},
	createListener: function(fn, scope) {
		var obj = {
			fn: fn,
			scope: scope
		}
		obj.fireFn = fn;   //这里先忽略target、delay、single、buffer的处理
		return obj;
	},
	fire: function() {
		var option = Ext.toArray(arguments);
		var len = this.listeners.length;
		while(len--) {
			this.fireing = true; //表示已经是执行状态了
			var fn = this.listeners[len];
			if(fn.fireFn.apply(fn.scope || this.scope, option) === false) {   //第一个参数是给响应函数指明作用域如果fn.scope不存在就使用这个Event(click)的scope
				return (this.fireing = false);   //执行结束
			}
		}
		this.fireing = false; //如果listeners都执行完,就让this.fireing变成false
		return true;
	}
});

Ext.toArray = function(arg) {
	var agent = navigator.userAgent.toLowerCase();
	if(!(/opera/.test(agent)) && /msie/.test(agent)) {  //IE浏览器,不能使用Array.prototype.slice.call(arg,0);
		var array = [];
		for(var index = 0; index < arg.length; index++) {
			array[index] = arg[index];
		}
		return array;
	}else { //其他浏览器
		return Array.prototype.slice.call(arg,0);
	}
}

Ext.extend = function(target, source, obj) {
	if(Ext.isObject(source)) {
		obj = source;
		source = target;
		target = obj.constructor? obj.constructor : function() {
			source.apply(this,arguments);						
		}
	}
	var fn = function() {};
	fn.prototype = source.prototype;;
	target.prototype = new fn();
	target.prototype.constructor = target;
	target.prototype.superclass = source.prototype;
	for(var key in obj) {
		target.prototype[key] = obj[key];
	}
	target.extend = function(source, obj) {    //给这个继承的组件提供一个extend方法
		Ext.extend(target,source,obj);
	}
	target.superclass = function() {          //定义一个返回superclass的方法
		return source.prototype; 
	}
	return target;
}

Ext.MyEvent = function() {
	this.name = 'stray';
	this.time = '2015-4-27';
	this.addEvent('show','read');
	Ext.MyEvent.prototype.superclass.constructor.call(this,arguments); //这一句代码挺关键的,主要是执行Ext.Observable构造函数
};
Ext.extend(Ext.MyEvent, Ext.Observable, {
	addListeners: {
		show: function() {
			alert('由'+ this.name + '在' + this.time + '提供');  //这里为什么可以使用this? 上边fire函数中已经指明了作用域scope
		},
		read: function() {
			alert('正在操作read响应函数');		
		}
	}
});

window.onload = function() {
	var myevent = new Ext.MyEvent();
	Ext.get('logonbox').addListener('click', function() {   //这里才和html原生的消息事件进行绑定
		myevent.fireEvent('show');
	});
	Ext.get('logonbox').addListener('dblclick', function() {   //这里才和html原生的消息事件进行绑定
		myevent.fireEvent('read');
	});
}

</script>
</head>
<body>
<div id='logonbox' >11111111</div>
</body>
</html>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值