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

js事件(2)

 
阅读更多
<html>
<head>
	<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
	<title>JS事件</title>
	<script src="http://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
	<style>
	</style>
</head>
<body>
	<input id="btn1" type="button" value="click1" />
	<input id="btn2" type="button" value="click2" />
	<input id="btn3" type="button" value="click3" />
</body>
</html>

<script type="text/javascript">
	//兼容ie浏览器测试
	var console = console || {};
	console.log = console.log || function(a){
		alert(a);
	}

	/*
	观察者模式,是一种一对多的关系,由发布者和订阅者组成,
	可以简单对应到事件和事件触发后回调的函数,可以说事件是按照观察者模式设计的.
	*/

	/*
	自定义事件,其实就是观察者模式的一个例子.
	说通俗点就是如果程序运行到某个地方,我们希望程序立刻运行绑定的方法.
	比如,点击某个按钮希望跳转到下一页.
	比如,当某一个条件改变的时候,立刻响应一个函数,弹出个提示框啥的.
	*/
	var targetEvent = function(){
		//事件处理
		function eventHandle(dom,type,fn,t){
			switch(t){
				case 1:
					//绑定事件
					//事件可以通过dom属性直接绑定,那我们是否可以把事件就当做dom的一个属性!
					dom[type] = fn;
				break;
				case 2:
					//触发事件
					if(typeof dom[type] == "function"){
						dom[type]();
					}
				break;
				case 3:
					//删除事件
					delete dom[type];
				break;
			}
		}

		//dom分析
		function analyze(dom,type,fn,t){
			//判断dom是否有多个
			if(dom.length){
				for(var i = 0,len = dom.length; i < len; i++){
					var el = dom[i];
					//判断是否是dom
					if(el && el.nodeName){
						//绑定事件
						eventHandle(dom,type,fn,t);
					}
				}
			}
			else{
				//判断是否是dom
				if(dom && dom.nodeName){
					//绑定事件
					eventHandle(dom,type,fn,t);
				}
			}
		}

		//绑定事件
		function bind(dom,type,fn){
			analyze(dom,type,fn,1);
		}

		//触发事件
		function trigger(dom,type){
			analyze(dom,type,{},2);
		}

		//删除事件
		function remove(dom,type){
			analyze(dom,type,{},3);
		}

		return {
			bind:bind,
			trigger:trigger,
			remove:remove
		}
	}();

	/*

	var btn1 = document.getElementById("btn1");
	//注册自定义事件
	targetEvent.bind(btn1,"myclick",function(){
		console.log("myclick");
	});
	//触发事件
	targetEvent.trigger(btn1,"myclick");

	var btns = document.getElementsByTagName("input");
	//注册自定义事件
	targetEvent.bind(btns,"btnclick",function(){
		console.log("btnclick");
	});
	//触发事件
	targetEvent.trigger(btns,"btnclick");

	*/

	/*
	这就是我理解的最简单的自定义事件了,其实在我看来这并没有太大的实际意义.
	前面说到事件是符合观察者模式的,但是这个自定义事件的对象,虽然有那么点意思,但不是全符合订阅加订阅者的关系.
	你看在执行触发事件的时候,还需要传入btns(相当于订阅对象).
	我所理解的观察者,订阅和订阅者应该是完全没有关系的.
	也就是说,我们在执行触发事件的时候,不应该传入btns,
	而是应该让订阅自己处理,有多少订阅者订阅了这些事件,然后挨个触发.
	顺着这个思路,再改改.
	*/

	var targetEvent = function(){
		//事件类型数据保存
		var handler = {};
		//事件dom数据保存
		var doms = {};

		//事件处理
		function eventHandle(t,type,dom,fn){
			switch(t){
				case 1:
					//绑定事件
					//事件可以通过dom属性直接绑定,那我们是否可以把事件就当做dom的一个属性!
					dom[type] = fn;
					//保存事件数据
					if(!(handler[type] instanceof Array)){
						handler[type] = [];
						doms[type] = [];
					}
					handler[type].push(dom[type]);
					doms[type].push(dom);
				break;
				case 2:
					//触发事件
					var dom = handler[type];
					if(dom instanceof Array){
						for(var i = 0,len = dom.length; i < len; i++){
							var fun = dom[i];
							if(typeof fun == "function"){
								fun();
							}
						}
					}
				break;
				case 3:
					//删除事件
					var dom = handler[type];
					if(dom instanceof Array){
						for(var i = 0,len = dom.length; i < len; i++){
							if(typeof dom[i] == "function"){
								//删除绑定dom的属性
								delete doms[type][i][type];
								//删除数据
								handler[type].splice(i,1);
								//删除数组之后,下标长度也会修改
								i--;
								len--;
							}
						}
					}
				break;
			}
		}

		//dom分析
		function analyze(t,dom,type,fn){
			//判断dom是否有多个
			if(dom.length){
				for(var i = 0,len = dom.length; i < len; i++){
					var el = dom[i];
					//判断是否是dom
					if(el && el.nodeName){
						//绑定事件
						eventHandle(t,type,dom,fn);
					}
				}
			}
			else{
				//判断是否是dom
				if(dom && dom.nodeName){
					//绑定事件
					eventHandle(t,type,dom,fn);
				}
			}
		}

		//绑定事件
		function bind(dom,type,fn){
			analyze(1,dom,type,fn);
		}

		//触发事件
		function trigger(type){
			eventHandle(2,type);
		}

		//删除事件
		function remove(type){
			eventHandle(3,type);
		}

		return {
			bind:bind,
			trigger:trigger,
			remove:remove
		}
	}();

	var btn1 = document.getElementById("btn1");
	//注册自定义事件
	targetEvent.bind(btn1,"myclick",function(){
		console.log("myclick1");
	});
	//触发事件
	targetEvent.trigger("myclick");
	//移除事件
	targetEvent.remove("myclick");


	var btns = document.getElementsByTagName("input");
	//注册自定义事件
	targetEvent.bind(btns,"myclick",function(){
		console.log("myclick2");
	});
	//触发事件
	targetEvent.trigger("myclick");

	/*
	这样看起来就比较像观察者了,我们有很多dom都订阅了myclick,
	所以只要触发了myclick,所有的myclick订阅者都能收到消息.
	*/

	/*
	任何一种模式,在我看来都只是一种思维方式,在软件开发过程中,通过这些方式去解决一些特定的问题.
	观察者模式需要有,订阅,派发,删除和订阅者几个要素,只要想明白了这几个要素的关系就不难组织代码.
	*/
	var observer = function(){
		//角色
		var subject = {};

		//订阅处理
		function handler(t,type,obj,fn){
			switch(t){
				case 1:
					//注册订阅
					obj[type] = fn;
					//保存事件数据
					if(!(subject[type] instanceof Array)){
						subject[type] = [];
					}
					subject[type].push(obj[type]);
				break;
				case 2:
					//派发消息
					var obj = subject[type];
					if(obj instanceof Array){
						for(var i = 0,len = obj.length; i < len; i++){
							var fun = obj[i];
							if(typeof fun == "function"){
								fun();
							}
						}
					}
				break;
				case 3:
					//删除订阅
					var obj = subject[type];
					if(obj instanceof Array){
						for(var i = 0,len = obj.length; i < len; i++){
							if(typeof obj[i] == "function"){
								//删除数据
								subject[type].splice(i,1);
								//删除数组之后,下标长度也会修改
								i--;
								len--;
							}
						}
					}
				break;
			}
		}

		//注册订阅
		function register(obj,type,fn){
			handler(1,type,obj,fn);
		}

		//派发消息
		function trigger(type){
			handler(2,type);
		}

		//删除订阅
		function remove(type){
			handler(3,type);
		}

		return {
			register:register,
			trigger:trigger,
			remove:remove
		}
	}();

	//观察者1
	function Class1(){
		this.say = function(){
			console.log("class1 say");
		}
	}

	//观察者2
	function Class2(){
		this.say = function(){
			console.log("class2 say");
		}
	}

	var c1 = new Class1();
	var c2 = new Class2();
	//注册订阅
	observer.register(c1,"valuechange",c1.say);
	observer.register(c2,"valuechange",c2.say);

	//派发订阅
	observer.trigger("valuechange");

	//删除订阅
	observer.remove("valuechange");

	/*
	知识点:
	1.自定义事件实现方法.
	2.观察者模式介绍.
	*/
</script>

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics