js 高级应用 自定义事件
Javascript与浏览器交互的途径主要是事件的形式。事件是一种观察者的设计模式,对象可以发布时间,然后其它对象可以观察该对象,等待这些时刻到来并通过运行代码来响应。
观察者模式主要由主体和观察者组成。主体负责发布事件,同时观察者通过订阅这些事件来观察该主体。该模式的一个关键概念是主体并不知道观察者的任何事情,也就是说它可以独自存在并正常运行即使观察者不存在。从另一方面来讲观察者知道主体并能注册事件的回调函数(事件处理程序)。
事件是与DOM交互的最常用的方式,但也可以用于非DOM的代码中—通过实现自定义事件。自定义事件的机制其实就是创建一个可以管理事件的对象。让其他对象监听那些事件。
1 function EventTarget(){ 2 this.handles={}; 3 } 4 EventTarget.prototype = { 5 constructor: EventTarget, 6 addHandler:function(type,fn){ 7 if(!(this.handles[type] instanceof Array)){ 8 this.handles[type] = []; 9 } 10 this.handles[type].push(fn); 11 }, 12 fire:function(event){ 13 if(!event.target){ 14 event.target = this; 15 } 16 if(this.handles[event.type] instanceof Array){ 17 var handles = this.handles[event.type]; 18 for(var i=0,len=handles.length;i<len;i++){ 19 handles[i](event); 20 } 21 } 22 }, 23 removeHandler:function(type,fn){ 24 if (this.handles[type] instanceof Array) { 25 var handles = this.handles[type]; 26 for (var i =0,len = handles.length;i<len;i++) { 27 if(handles[i] == fn){ 28 break; 29 } 30 }; 31 handles.splice(i,1); 32 }; 33 } 34 }
EventTarget有一个单独的属性,用于储存事件处理程序,三个方法中,addHandler用于添加事件处理程序,将事件添加到相应的事件型号的数组下,用push添加到数组的最后。removeHandler用于移除相应的事件。fire用于触发相应事件类型下的所有事件,通过for的形式循环触发。
要使用这个自定义事件类型,可以通过以下这个方式。
1 function Person(name){ 2 this.name = name; 3 this.etarget = new EventTarget(); 4 } 5 Person.prototype = { 6 constructor:Person, 7 say:function(message){ 8 this.etarget.fire({type:‘message‘,target:this,message:message}); 9 }, 10 addMess:this.addMess = function(type,fn){ 11 this.etarget.addHandler(type,fn); 12 } 13 }
这样就可以做到事件监听机制的使用了。在这里,一旦调用say方法,便触发了事件,它包含了事件的细节。同时在其中fire不是公开调用的,这段代码可以按以下方式使用。
1 var person = new Person(‘Tom‘); 2 person.addMess(‘message‘,function(event){ 3 console.log(event.target.name+‘says:‘+event.message); 4 }) 5 person.say(‘hello!!!‘);
EXAMPLE:拖放
拖放是一种常见的用户界面模式,在HTML5中也有类似的API实现了该功能,在这里我们会用javascript和html来实现这个功能。
拖放的核心函数调用就是mousemove了,通过鼠标移动不断触发,并不断调整位置,实现拖动的连续性。
1 var Dragdrop = (function(){ 2 var dragging = null; 3 dragHandler = function(event){ 4 var event = event||window.event, 5 target = event.target ||event.srcElement; 6 switch(event.type){ 7 case ‘mousedown‘: 8 if(target.className.indexOf(‘draggable‘) > -1){ 9 dragging = target; 10 } 11 break; 12 case ‘mousemove‘: 13 if(dragging != null){ 14 dragging.style.left = event.pageX+‘px‘; 15 dragging.style.top = event.pageY+‘px‘; 16 } 17 break; 18 case ‘mouseup‘: 19 dragging = null; 20 break; 21 } 22 }; 23 return {enable : function(){ 24 document.addEventListener(‘mouseup‘,dragHandler,false); 25 document.addEventListener(‘mousemove‘,dragHandler,false); 26 document.addEventListener(‘mousedown‘,dragHandler,false); 27 }, 28 disable: function(){ 29 document.removeEventListener(‘mouseup‘,dragHandler,false); 30 document.removeEventListener(‘mousemove‘,dragHandler,false); 31 document.removeEventListener(‘mousedown‘,dragHandler,false); 32 }} 33 })();
现在还不能实现真正的交互,因为我们无法知道到底什么时候开始拖动,拖动结束。这时就可以用自定义事件来指示这个事件的发生。实现方式主要是先创建一个新的EventTarget的对象,然后添加enable和disable方法,最后返回这个对象:
1 var Dragdrop = (function(){ 2 var dragEvent = new EventTarget(), 3 dragging = null; 4 dragHandler = function(event){ 5 var event = event||window.event, 6 target = event.target ||event.srcElement; 7 switch(event.type){ 8 case ‘mousedown‘: 9 if(target.className.indexOf(‘draggable‘) > -1){ 10 dragging = target; 11 dragEvent.fire({target:dragging,type:‘dragstart‘}); 12 } 13 break; 14 case ‘mousemove‘: 15 if(dragging != null){ 16 dragging.style.left = event.pageX+‘px‘; 17 dragging.style.top = event.pageY+‘px‘; 18 dragEvent.fire({target:dragging,type:‘dragmove‘,pos:{left:event.pageX,top:event.pageY}}); 19 } 20 break; 21 case ‘mouseup‘: 22 dragging = null; 23 dragEvent.fire({target:dragging,type:‘dragstop‘}); 24 break; 25 } 26 }; 27 dragEvent.enable = function(){ 28 document.addEventListener(‘mouseup‘,dragHandler,false); 29 document.addEventListener(‘mousemove‘,dragHandler,false); 30 document.addEventListener(‘mousedown‘,dragHandler,false); 31 }; 32 dragEvent.disable = function(){ 33 document.removeEventListener(‘mouseup‘,dragHandler,false); 34 document.removeEventListener(‘mousemove‘,dragHandler,false); 35 document.removeEventListener(‘mousedown‘,dragHandler,false); 36 }; 37 return dragEvent; 38 })();
在对代码的主要改动处都以特殊的字体标出来了,这些改动使得Dragdrop对象支持了事件,使用方式如下:
1 Dragdrop.addHandler(‘dragstart‘,function(event){ 2 console.log(‘drag start!‘); 3 }); 4 Dragdrop.addHandler(‘dragmove‘,function(event){ 5 console.log(‘dragmove,pos:‘+event.pos.left+‘:‘+event.pos.top); 6 }); 7 Dragdrop.addHandler(‘dragstop‘,function(event){ 8 console.log(‘dragstop‘); 9 });
这样就死的Dragdrop对象更加健壮了,就可以处理一下复杂的拖放事件了。
所有代码集合如下:
<html> <head> <script type="text/javascript"> function EventTarget(){ this.handles={}; } EventTarget.prototype = { constructor: EventTarget, addHandler:function(type,fn){ if(!(this.handles[type] instanceof Array)){ this.handles[type] = []; } this.handles[type].push(fn); }, fire:function(event){ if(!event.target){ event.target = this; } if(this.handles[event.type] instanceof Array){ var handles = this.handles[event.type]; for(var i=0,len=handles.length;i<len;i++){ handles[i](event); } } }, removeHandler:function(type,fn){ if (this.handles[type] instanceof Array) { var handles = this.handles[type]; for (var i =0,len = handles.length;i<len;i++) { if(handles[i] == fn){ break; } }; handles.splice(i,1); }; } } var Dragdrop = (function(){ var dragEvent = new EventTarget(), dragging = null; dragHandler = function(event){ var event = event||window.event, target = event.target ||event.srcElement; switch(event.type){ case ‘mousedown‘: if(target.className.indexOf(‘draggable‘) > -1){ dragging = target; dragEvent.fire({target:dragging,type:‘dragstart‘}); } break; case ‘mousemove‘: if(dragging != null){ dragging.style.left = event.pageX+‘px‘; dragging.style.top = event.pageY+‘px‘; dragEvent.fire({target:dragging,type:‘dragmove‘,pos:{left:event.pageX,top:event.pageY}}); } break; case ‘mouseup‘: dragging = null; dragEvent.fire({target:dragging,type:‘dragstop‘}); break; } }; dragEvent.enable = function(){ document.addEventListener(‘mouseup‘,dragHandler,false); document.addEventListener(‘mousemove‘,dragHandler,false); document.addEventListener(‘mousedown‘,dragHandler,false); }; dragEvent.disable = function(){ document.removeEventListener(‘mouseup‘,dragHandler,false); document.removeEventListener(‘mousemove‘,dragHandler,false); document.removeEventListener(‘mousedown‘,dragHandler,false); }; return dragEvent; })(); /*function Person(name){ this.name = name; this.etarget = new EventTarget(); } Person.prototype = { constructor:Person, say:function(message){ this.etarget.fire({type:‘message‘,target:this,message:message}); }, addMess:this.addMess = function(type,fn){ this.etarget.addHandler(type,fn); } } var person = new Person(‘Tom‘); person.addMess(‘message‘,function(event){ console.log(event.target.name+‘says:‘+event.message); }) person.say(‘hello!!!‘);*/ Dragdrop.addHandler(‘dragstart‘,function(event){ console.log(‘drag start!‘); }); Dragdrop.addHandler(‘dragmove‘,function(event){ console.log(‘dragmove,pos:‘+event.pos.left+‘:‘+event.pos.top); }); Dragdrop.addHandler(‘dragstop‘,function(event){ console.log(‘dragstop‘); }); </script> </head> <body> <div class="draggable" style="position:absolute;width:100px;height:100px;background:silver"></div> </body> </html>
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。