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

在ExtJs源码分析与学习—ExtJs事件机制(一)中分析了ExtJs对原生浏览器事件的封装。这篇进一步分析ExtJs对事件的封装和扩充。ExtJs会对浏览器本身的事件进行转换,是通过类Ext.EventObject来实现的,该类中通过自执行匿名函数返回Ext.EventObjectImpl对象,该对象用到了Ext.lib.Event(对原生浏览器事件的扩展)。

 

Js代码    收藏代码
  1. Ext.EventObject = function(){  
  2.     var E = Ext.lib.Event,  
  3.     …  
  4.     Ext.EventObjectImpl = function(e){  
  5.         if(e){  
  6.             this.setEvent(e.browserEvent || e);  
  7.         }  
  8.     };  
  9.   
  10.     Ext.EventObjectImpl.prototype = {  
  11.        …  
  12. };  
  13.   
  14.     return new Ext.EventObjectImpl();  
  15. }();  

 

下面看Ext.EventObject中代码的实现

 

Js代码    收藏代码
  1. // safari keypress events for special keys return bad keycodes  
  2. safariKeys = {  
  3.             3 : 13, // enter  
  4.             63234 : 37, // left  
  5.             63235 : 39, // right  
  6.             63232 : 38, // up  
  7.             63233 : 40, // down  
  8.             63276 : 33, // page up  
  9.             63277 : 34, // page down  
  10.             63272 : 46, // delete  
  11.             63273 : 36, // home  
  12.             63275 : 35  // end  
  13.         },  

 该对象是为了兼容旧版本safari浏览器对部分键的按键事件返回值的处理,与其他浏览器的统一。

 

Js代码    收藏代码
  1. // normalize button clicks  
  2.  btnMap = Ext.isIE ? {1:0,4:1,2:2} : {0:0,1:1,2:2};  

 由于IE浏览器与其他浏览器的按键值(e.button)不同,所以定义该对象是为了实现所有浏览器的兼容。兼容后,0为左键,1为中键,2为右键。

接下来是类Ext.EventObjectImpl的定义

 

Js代码    收藏代码
  1. Ext.EventObjectImpl = function(e){  
  2.         if(e){  
  3.             this.setEvent(e.browserEvent || e);  
  4.         }  
  5. };  

 该类中对浏览器原生事件e进行了包装,调用了private method setEvent,setEvent是定义在Ext.EventObjectImpl.prototype下的

 

Js代码    收藏代码
  1. /** @private */  
  2. setEvent : function(e){  
  3.     var me = this;  
  4.     if(e == me || (e && e.browserEvent)){ // already wrapped  
  5.         return e;  
  6.     }  
  7.     me.browserEvent = e;//把浏览器的原始事件保存到browserEvent中,可以作为是否包装的标识  
  8.     if(e){  
  9.         // normalize buttons  
  10.         //该段代码处理了不同按键返回的e.button  
  11.         me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);//e.which原本是键盘事件  
  12.         if(clickRe.test(e.type) && me.button == -1){  
  13.             me.button = 0;  
  14.         }  
  15.         me.type = e.type;//事件名  
  16.         //三个功能组合键  
  17.         me.shiftKey = e.shiftKey;  
  18.         // mac metaKey behaves like ctrlKey  
  19.         me.ctrlKey = e.ctrlKey || e.metaKey || false;  
  20.         me.altKey = e.altKey;  
  21.           
  22.         //键盘事件的keywode,and charcode   
  23.         // in getKey these will be normalized for the mac  
  24.         me.keyCode = e.keyCode;  
  25.         me.charCode = e.charCode;  
  26.           
  27.         // cache the target for the delayed and or buffered events  
  28.         //事件目标,E.getTarget(e)处理了不同浏览器的返回结果  
  29.         me.target = E.getTarget(e);  
  30.         // same for XY  
  31.         me.xy = E.getXY(e);//Ext自定义的坐标属性  
  32.     }else{//如果没有传入事件,则恢复属性为原始值  
  33.         me.button = -1;  
  34.         me.shiftKey = false;  
  35.         me.ctrlKey = false;  
  36.         me.altKey = false;  
  37.         me.keyCode = 0;  
  38.         me.charCode = 0;  
  39.         me.target = null;  
  40.         me.xy = [0, 0];  
  41.     }  
  42.     return me;  
  43. },  

 该方法首先判断事件是否包装过,如已经包装了,则直接返回该包装的事件。
 me.browserEvent = e;//把浏览器的原始事件保存到browserEvent中
 me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);//e.which原本是键盘事件
     if(clickRe.test(e.type) && me.button == -1){
         me.button = 0;
 }
该段代码处理了不同按键返回不同的e.button
其他代码的功能,可参见代码注释

 

 

接着看stopEvent方法

 

Js代码    收藏代码
  1. stopEvent : function(){  
  2.             var me = this;  
  3.             if(me.browserEvent){  
  4.                 if(me.browserEvent.type == 'mousedown'){  
  5.                     Ext.EventManager.stoppedMouseDownEvent.fire(me);  
  6.                 }  
  7.                 E.stopEvent(me.browserEvent);  
  8.             }  
  9.         },  

 

停止事件(preventDefault和stopPropagation)。用来停止事件冒泡,阻止元素默认行为。需要说明的是对mousedown事件做了特殊处理Ext.EventManager.stoppedMouseDownEvent 实际是Ext.util.Event类的一个实例对象。如pub.stoppedMouseDownEvent = new Ext.util.Event();后续讲到Ext.EventManager时,会讲fire方法。

 

Js代码    收藏代码
  1. /** 
  2.         * Prevents the browsers default handling of the event. 
  3.         */  
  4.        preventDefault : function(){  
  5.            if(this.browserEvent){  
  6.                E.preventDefault(this.browserEvent);  
  7.            }  
  8.        },  
  9.   
  10.        /** 
  11.         * Cancels bubbling of the event. 
  12.         */  
  13.        stopPropagation : function(){  
  14.            var me = this;  
  15.            if(me.browserEvent){  
  16.                if(me.browserEvent.type == 'mousedown'){  
  17.                    Ext.EventManager.stoppedMouseDownEvent.fire(me);  
  18.                }  
  19.                E.stopPropagation(me.browserEvent);  
  20.            }  
  21.        },  

 对preventDefault(阻止浏览器默认行为处理事件)和stopPropagation(取消事件冒泡)在该类中的实现,实际上还是调用Ext.lib.Event中的原生方法

 

接着看其他代码

 

Js代码    收藏代码
  1. /** 
  2.         * 返回该事件键盘字符代码 
  3.         * Gets the character code for the event. 
  4.         * @return {Number} 键盘代码 
  5.         */  
  6.        getCharCode : function(){  
  7.            return this.charCode || this.keyCode;  
  8.        },  
  9.   
  10.        /** 
  11.         * 返回一个常规化的事件键盘代码,对Safari进行了特殊处理 
  12.         * Returns a normalized keyCode for the event. 
  13.         * @return {Number} The key code 
  14.         */  
  15.        getKey : function(){  
  16.            var k = this.keyCode || this.charCode;  
  17.            return Ext.isSafari ? (safariKeys[k] || k) : k;  
  18.        },  
  19.   
  20.        /** 
  21.         * 获取事件X坐标。 
  22.         * Gets the x coordinate of the event. 
  23.         * @return {Number} 
  24.         */  
  25.        getPageX : function(){  
  26.            return this.xy[0];  
  27.        },  
  28.   
  29.        /** 
  30.         * 获取事件Y坐标。 
  31.         * Gets the y coordinate of the event. 
  32.         * @return {Number} 
  33.         */  
  34.        getPageY : function(){  
  35.            return this.xy[1];  
  36.        },  
  37.   
  38.        /** 
  39.         * 获取事件的时间。 
  40.         * Gets the time of the event. 
  41.         * @return {Number} 
  42.         */  
  43.        getTime : function(){  
  44.            if(this.browserEvent){  
  45.                return E.getTime(this.browserEvent);  
  46.            }  
  47.            return null;  
  48.        },  
  49.          
  50.        /** 
  51.         * 获取事件的页面坐标。 
  52.         * Gets the page coordinates of the event. 
  53.         * @return {Array} xy值,格式[x, y]。The xy values like [x, y] 
  54.         */  
  55.        getXY : function(){  
  56.            return this.xy;  
  57.        },  
  58.   
  59.       /** 
  60.         * 获取事件的目标对象。 
  61.         * Gets the target for the event. 
  62.         * @param {String} selector (可选的) 一个简易的选择符,用于筛选目标或查找目标的父级元素。(optional) A simple selector to filter the target or look for an ancestor of the target 
  63.         * @param {Number/Mixed} maxDepth (可选的)搜索的最大深度(数字或是元素,默认为10||document.body)。(optional) The max depth to search as a number or element (defaults to 10 || document.body) 
  64.         * @param {Boolean} returnEl (可选的) True表示为返回Ext.Element的对象而非DOM节点。(optional) True to return a Ext.Element object instead of DOM node 
  65.         * @return {HTMLelement} 
  66.         */  
  67.        getTarget : function(selector, maxDepth, returnEl){  
  68.            return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);  
  69.        },  
  70.   
  71.   
  72.        /** 
  73.         * 获取相关的目标对象。 
  74.         * Gets the related target. 
  75.         * @return {HTMLElement} 
  76.         */  
  77.        getRelatedTarget : function(){  
  78.            return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;  
  79.        },  
  80.   
  81.        /** 
  82.         * 常规化鼠标滚轮的有限增量(速度)。 
  83.         * IE/Safari/Chrome/Opera中使用事件对象的wheelDelta属性,Firefox则使用detail属性。 
  84.        属性的方向值也不一样,IE向前滚 > 0为120,相反在-120,Firefox向后滚 > 0为3,相反则-3。 
  85.         * Normalizes mouse wheel delta across browsers 
  86.         * @return {Number} The delta 
  87.         */  
  88.        getWheelDelta : function(){  
  89.            var e = this.browserEvent;  
  90.            var delta = 0;  
  91.            if(e.wheelDelta){ /* IE/Opera. */  
  92.                delta = e.wheelDelta/120;  
  93.            }else if(e.detail){ /* Mozilla case. */  
  94.                delta = -e.detail/3;  
  95.            }  
  96.            return delta;  
  97.        },  

getTarget 方法用到了Ext.fly,一个关键的方法,利用共享模式实现的,后续待讲

 

下面看方法within

 

Js代码    收藏代码
  1. within : function(el, related, allowEl){  
  2.       if(el){  
  3.           var t = this[related ? "getRelatedTarget" : "getTarget"]();  
  4.           return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));  
  5.       }  
  6.       return false;  
  7.   }  

如果该事件的目标对象是el的子元素,则返回true;如果allowEl设为true时,该事件的目标对象等于el也返回true。关于这个方法的理解,请看例子:

 

Html代码    收藏代码
  1. >  
  2. <html>  
  3.     <head>  
  4.         <title>Ext.EventObject.within method demotitle>  
  5.         <meta http-equiv="content-type" content="text/html; charset=UTF-8">  
  6.         <link rel="stylesheet" type="text/css"  
  7.             href="../ext-3.3.1/resources/css/ext-all.css" />  
  8.         <style type="text/css">  
  9.             div {  
  10.                 border: 1px solid blue;  
  11.                 padding: 40px;  
  12.                 margin: 10px;  
  13.             }  
  14.         style>  
  15.           
  16.         <script type="text/javascript"  
  17.             src="../ext-3.3.1/adapter/ext/ext-base-debug.js">script>  
  18.         <script type="text/javascript"  
  19.             src="../ext-3.3.1/ext-all-debug-w-comments.js">script>  
  20.         <script type="text/javascript"  
  21.             src="../ext-3.3.1/src/locale/ext-lang-zh_CN.js">script>  
  22.         <script type="text/javascript" src="../ext-3.3.1/src/debug.js">script>  
  23.           
  24.         <script type="text/javascript">  
  25.             Ext.onReady(function() {  
  26.               Ext.BLANK_IMAGE_URL = '../ext-3.3.1/resources/images/default/s.gif';  
  27.               Ext.QuickTips.init();  
  28.                     Ext.getBody().on('click', function(e){  
  29.                         if(e.within('some-el')){//如果该事件的目标对象是some-el的子元素,则返回true  
  30.                             alert('是在some-el的孩子节点上点击的!');  
  31.                         }else{  
  32.                             alert('你的点击不是some-el的孩子节点');  
  33.                         }  
  34.                     });  
  35.               
  36.                     Ext.getBody().on('click', function(e,t){  
  37.                         if((t.id == 'some-el') && !e.within(t, true)){//如果allowEl设为true时,该事件的目标对象等于el也返回true  
  38.                             alert('直接在some-el上点击了鼠标!');  
  39.                         }  
  40.                     });  
  41.              });  
  42.           
  43.         script>  
  44.     head>  
  45.   
  46.     <body>  
  47.         <div id="some-el">  
  48.             <div id="some-el2">  
  49.                 Ext.EventObject.within demo  
  50.             div>  
  51.         div>  
  52.         <br/>  
  53.         <div id="some-el3">  
  54.             <div id="some-el4">  
  55.                 不是some-el节点  
  56.             div>  
  57.         div>  
  58.     body>  
  59. html>  
 

以上介绍了Ext事件 Ext.EventObject 对浏览器原生事件的包装和扩展,实现了个浏览器之间的兼容。

你可能感兴趣的:(extjs)