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>
View Code

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。