ExtJs源码分析与学习—ExtJs事件机制(五)

最近一直忙着做产品,所以好久没有写文章了,下面接着把ExtJs事件机制最后一点内容写完。主要是介绍Ext提供的三个辅助实现事件类——快捷键、导航键和鼠标按键事件。

 

快捷键 Ext.KeyMap 

    该功能的实现被封装在类Ext.KeyMap中

Js代码   收藏代码
  1. Ext.KeyMap = function(el, config, eventName){  
  2.     this.el  = Ext.get(el);  
  3.     this.eventName = eventName || "keydown";  
  4.     this.bindings = [];  
  5.     if(config){  
  6.         this.addBinding(config);  
  7.     }  
  8.     this.enable();  
  9. };  

    该类实现分为三步,首先找到注册快捷键的元素el,然后把config参数转换为事件的监听函数this.addBinding(config),最后再注册该监听函数this.enable()。先看addBinding方法的实现

 

Js代码   收藏代码
  1. addBinding : function(config){  
  2.         if(Ext.isArray(config)){  
  3.             Ext.each(config, function(c){  
  4.                 this.addBinding(c);  
  5.             }, this);  
  6.             return;  
  7.         }  
  8.         var keyCode = config.key,  
  9.             fn = config.fn || config.handler,  
  10.             scope = config.scope;  
  11.   
  12.     if (config.stopEvent) {  
  13.         this.stopEvent = config.stopEvent;      
  14.     }     
  15.   
  16.         if(typeof keyCode == "string"){  
  17.             var ks = [];  
  18.             var keyString = keyCode.toUpperCase();  
  19.             for(var j = 0, len = keyString.length; j < len; j++){  
  20.                 ks.push(keyString.charCodeAt(j));  
  21.             }  
  22.             keyCode = ks;  
  23.         }  
  24.         var keyArray = Ext.isArray(keyCode);  
  25.           
  26.         //代理按键的监听处理函数,对配置对象中的fn/handle函数进行代理加工处理  
  27.         var handler = function(e){  
  28.             //如果指定'shift', 'ctrl', 'alt',而事件对象没有按下指定的'shift', 'ctrl', 'alt',那么就不进行处理  
  29.             if(this.checkModifiers(config, e)){  
  30.                 var k = e.getKey();  
  31.                 if(keyArray){  
  32.                     for(var i = 0, len = keyCode.length; i < len; i++){  
  33.                         if(keyCode[i] == k){  
  34.                           if(this.stopEvent){  
  35.                               e.stopEvent();  
  36.                           }  
  37.                           fn.call(scope || window, k, e);  
  38.                           return;  
  39.                         }  
  40.                     }  
  41.                 }else{  
  42.                     if(k == keyCode){  
  43.                         if(this.stopEvent){  
  44.                            e.stopEvent();  
  45.                         }  
  46.                         fn.call(scope || window, k, e);  
  47.                     }  
  48.                 }  
  49.             }  
  50.         };  
  51.         this.bindings.push(handler);  
  52.     },  

 

 config配置项支持以下属性

属性    类型             描述
----------  ---------------  ----------------------------------------------------------------------
key         String/Array      进行处理的单个keycode或keycodes组成的数组
shift       Boolean           True:只有shift按下的的同时处理key (默认false)
ctrl        Boolean           True:只有ctrl按下的的同时处理key (默认false)
handler     Function          当KeyMap找到预期的组合键时所执行的函数
alt         Boolean           True:只有alt按下的的同时处理key (默认false)
fn          Function          当组合键按下后回调函数
scope       Object            回调函数的作用域
stopEvent   Boolean           用来停止事件冒泡,阻止元素默认行为。


再看enable方法,把事件注册到元素上

 

Js代码   收藏代码
  1. enable: function(){  
  2.         if(!this.enabled){  
  3.             this.el.on(this.eventName, this.handleKeyDown, this);  
  4.             this.enabled = true;  
  5.         }  
  6.     },  

为指定的el元素注册事件

例子:常用复制、剪切、粘贴的实现

 

Js代码   收藏代码
  1. var config = [{//剪切  
  2.         key : 'x',  
  3.         ctrl : true,  
  4.         fn : function() {  
  5.             //cut  
  6.         },  
  7.         scope : this  
  8.     },{//复制  
  9.         key : 'c',  
  10.         ctrl : true,  
  11.         fn : function() {  
  12.             //copy  
  13.         },  
  14.         scope : this  
  15.     },{//粘贴  
  16.         key : 'v',  
  17.         ctrl : true,  
  18.         fn : function() {  
  19.             //paste  
  20.         },  
  21.         scope : this  
  22.     },{//编辑  
  23.         key : 'abcdefghigklmnopqrstuvwxyz0123456789',  
  24.         ctrl : false,  
  25.         shift : false,  
  26.         alt : false,  
  27.         fn : function(k, e) {  
  28.             alert(k);  
  29.         },  
  30.         scope : this  
  31.     }];  
  32.   
  33. var map = new Ext.KeyMap("my-element", config);  

 

导航键 Ext.KeyNav

 

    导航键的实现被封装在类Ext.KeyNav中,首先看其构造函数

 

 

Js代码   收藏代码
  1. Ext.KeyNav = function(el, config){  
  2.     this.el = Ext.get(el);  
  3.     Ext.apply(this, config);  
  4.     if(!this.disabled){//如果被禁用则激活  
  5.         this.disabled = true;  
  6.         this.enable();//注册监听函数  
  7.     }  
  8. };  

    再看注册监听函数

 

Js代码   收藏代码
  1. enable: function() {  
  2.      if (this.disabled) {  
  3.          if (Ext.isSafari2) {  
  4.              // call stopKeyUp() on "keyup" event  
  5.              this.el.on('keyup'this.stopKeyUp, this);  
  6.          }  
  7.   
  8.          this.el.on(this.isKeydown()? 'keydown' : 'keypress'this.relay, this);  
  9.          this.disabled = false;  
  10.      }  
  11.  },  

      IE及其他一些浏览器的keyPress事件不会对非字母数字键进行冒泡,所以采用keyDown事件替代keyPress事件。而该事件的处理函数relay起了代理作用

 

Js代码   收藏代码
  1. relay : function(e){  
  2.         var k = e.getKey(),  
  3.             h = this.keyToHandler[k];  
  4.         if(h && this[h]){  
  5.             if(this.doRelay(e, this[h], h) !== true){  
  6.                 e[this.defaultEventAction]();  
  7.             }  
  8.         }  
  9.     },  

 

      KeyToHandler是键名和键值对应的hash表,通过event对象获得了键值之后,再和Ext.KeyNav类中12个导航键名比较,看看其是否为导航键,如果是,再看看有没有注册的处理函数,有才运行该监听函数。

该导航键共提供了12个,分别为
keyToHandler : {
        37 : "left",
        39 : "right",
        38 : "up",
        40 : "down",
        33 : "pageUp",
        34 : "pageDown",
        46 : "del",
        36 : "home",
        35 : "end",
        13 : "enter",
        27 : "esc",
        9  : "tab"
},

例子

 

Js代码   收藏代码
  1. var nav = new Ext.KeyNav("my-element", {  
  2.     "left" : function(e){  
  3.         this.moveLeft(e.ctrlKey);  
  4.     },  
  5.     "right" : function(e){  
  6.         this.moveRight(e.ctrlKey);  
  7.     },  
  8.     "enter" : function(e){  
  9.         this.save();  
  10.     },  
  11.     scope : this  
  12. });  

 

鼠标按住事件 Ext.util.ClickRepeater


     鼠标按住事件就是用鼠标按住某个元素,会根据指定的时间间隔来反复地执行同样的动作。该功能的实现被封装在类Ext.util.ClickRepeater,首先看构造函数

 

Js代码   收藏代码
  1. constructor : function(el, config){  
  2.         this.el = Ext.get(el);  
  3.         this.el.unselectable();//元素内容不能选择  
  4.   
  5.         Ext.apply(this, config);  
  6.   
  7.         this.addEvents(  
  8.         /** 
  9.          * @event mousedown 
  10.          * 当鼠标按下的时候触发。 
  11.          * Fires when the mouse button is depressed. 
  12.          * @param {Ext.util.ClickRepeater} this 
  13.          * @param {Ext.EventObject} e 
  14.          */  
  15.         "mousedown",  
  16.         /** 
  17.          * @event click 
  18.          * 当元素被按下接受到按下的消息的时候出发,比mousedown事件慢。 
  19.          * Fires on a specified interval during the time the element is pressed. 
  20.          * @param {Ext.util.ClickRepeater} this 
  21.          * @param {Ext.EventObject} e 
  22.          */  
  23.         "click",  
  24.         /** 
  25.          * @event mouseup 
  26.          * 当鼠标释放后触发。 
  27.          * Fires when the mouse key is released. 
  28.          * @param {Ext.util.ClickRepeater} this 
  29.          * @param {Ext.EventObject} e 
  30.          */  
  31.         "mouseup"  
  32.         );  
  33.   
  34.         if(!this.disabled){  
  35.             this.disabled = true;  
  36.             this.enable();  
  37.         }  
  38.   
  39.         // allow inline handler  
  40.         if(this.handler){  
  41.             this.on("click"this.handler,  this.scope || this);  
  42.         }  
  43.   
  44.         Ext.util.ClickRepeater.superclass.constructor.call(this);          
  45. },  

      该构造函数中调用了this.enable();来处理鼠标按下事件,然后如果配置项声明了handler处理函数,会把该函数注册到cilck事件中。下面看方法enable

 

Js代码   收藏代码
  1. enable: function(){  
  2.         if(this.disabled){  
  3.             this.el.on('mousedown'this.handleMouseDown, this);  
  4.             if (Ext.isIE){  
  5.                 this.el.on('dblclick'this.handleDblClick, this);  
  6.             }  
  7.             if(this.preventDefault || this.stopDefault){  
  8.                 this.el.on('click'this.eventOptions, this);  
  9.             }  
  10.         }  
  11.         this.disabled = false;  
  12.     },  

      该方法中给元素el注册了mousedown事件,如果是IE浏览器,还注册了dblclick事件,然后根据配置项来阻止默认或冒泡处理,下面看handleMouseDown

 

Js代码   收藏代码
  1. handleMouseDown : function(e){  
  2.         clearTimeout(this.timer);  
  3.         this.el.blur();//除去焦点  
  4.         if(this.pressClass){  
  5.             this.el.addClass(this.pressClass);  
  6.         }  
  7.         this.mousedownTime = new Date();  
  8.   
  9.         Ext.getDoc().on("mouseup"this.handleMouseUp, this);  
  10.         this.el.on("mouseout"this.handleMouseOut, this);  
  11.   
  12.         this.fireEvent("mousedown"this, e);  
  13.         this.fireEvent("click"this, e);  
  14.   
  15.         // Do not honor delay or interval if acceleration wanted.  
  16.         if (this.accelerate) {  
  17.             this.delay = 400;  
  18.         }  
  19.         this.timer = this.click.defer(this.delay || this.interval, this, [e]);  
  20. },  

      当用户在某个元素上按下鼠标时,首先让该元素失去焦点,改变样式,同时还分别为鼠标按键松开或移出注册了监听函数,最后按指定的间隔来推迟运行click函数

 

Js代码   收藏代码
  1. click : function(e){  
  2.         this.fireEvent("click"this, e);  
  3.         this.timer = this.click.defer(this.accelerate ?  
  4.             this.easeOutExpo(this.mousedownTime.getElapsed(),  
  5.                 400,  
  6.                 -390,  
  7.                 12000) :  
  8.             this.interval, this, [e]);  
  9. },  

 

     该函数递归调用click函数,如果设置了this.accelerate,时间间隔就会按一定的算法越运行越短,即运行click会越来越快。

你可能感兴趣的:(function,浏览器,object,String,ExtJs,Constructor)