首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > JavaScript >

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

2012-10-08 
ExtJs源码分析与学习—ExtJs事件机制(二)?????? 在ExtJs源码分析与学习—ExtJs事件机制(一)中分析了ExtJs对

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

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

?

Ext.EventObject = function(){    var E = Ext.lib.Event,    …    Ext.EventObjectImpl = function(e){        if(e){            this.setEvent(e.browserEvent || e);        }    };    Ext.EventObjectImpl.prototype = {       …};    return new Ext.EventObjectImpl();}();

?

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

?

// safari keypress events for special keys return bad keycodessafariKeys = {            3 : 13, // enter            63234 : 37, // left            63235 : 39, // right            63232 : 38, // up            63233 : 40, // down            63276 : 33, // page up            63277 : 34, // page down            63272 : 46, // delete            63273 : 36, // home            63275 : 35  // end        },

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

?

// normalize button clicks btnMap = Ext.isIE ? {1:0,4:1,2:2} : {0:0,1:1,2:2};

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

接下来是类Ext.EventObjectImpl的定义

?

Ext.EventObjectImpl = function(e){        if(e){            this.setEvent(e.browserEvent || e);        }};

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

?

        /** @private */        setEvent : function(e){            var me = this;            if(e == me || (e && e.browserEvent)){ // already wrapped                return e;            }            me.browserEvent = e;//把浏览器的原始事件保存到browserEvent中,可以作为是否包装的标识            if(e){                // normalize buttons            //该段代码处理了不同按键返回的e.button                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;                }                me.type = e.type;//事件名                //三个功能组合键                me.shiftKey = e.shiftKey;                // mac metaKey behaves like ctrlKey                me.ctrlKey = e.ctrlKey || e.metaKey || false;                me.altKey = e.altKey;                                //键盘事件的keywode,and charcode                 // in getKey these will be normalized for the mac                me.keyCode = e.keyCode;                me.charCode = e.charCode;                                // cache the target for the delayed and or buffered events                //事件目标,E.getTarget(e)处理了不同浏览器的返回结果                me.target = E.getTarget(e);                // same for XY                me.xy = E.getXY(e);//Ext自定义的坐标属性            }else{//如果没有传入事件,则恢复属性为原始值                me.button = -1;                me.shiftKey = false;                me.ctrlKey = false;                me.altKey = false;                me.keyCode = 0;                me.charCode = 0;                me.target = null;                me.xy = [0, 0];            }            return me;        },

?该方法首先判断事件是否包装过,如已经包装了,则直接返回该包装的事件。
?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方法

?

stopEvent : function(){            var me = this;            if(me.browserEvent){                if(me.browserEvent.type == 'mousedown'){                    Ext.EventManager.stoppedMouseDownEvent.fire(me);                }                E.stopEvent(me.browserEvent);            }        },

?

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

?

 /**         * Prevents the browsers default handling of the event.         */        preventDefault : function(){            if(this.browserEvent){                E.preventDefault(this.browserEvent);            }        },        /**         * Cancels bubbling of the event.         */        stopPropagation : function(){            var me = this;            if(me.browserEvent){                if(me.browserEvent.type == 'mousedown'){                    Ext.EventManager.stoppedMouseDownEvent.fire(me);                }                E.stopPropagation(me.browserEvent);            }        },

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

?

接着看其他代码

?

 /**         * 返回该事件键盘字符代码         * Gets the character code for the event.         * @return {Number} 键盘代码         */        getCharCode : function(){            return this.charCode || this.keyCode;        },        /**         * 返回一个常规化的事件键盘代码,对Safari进行了特殊处理         * Returns a normalized keyCode for the event.         * @return {Number} The key code         */        getKey : function(){            var k = this.keyCode || this.charCode;            return Ext.isSafari ? (safariKeys[k] || k) : k;        },        /**         * 获取事件X坐标。         * Gets the x coordinate of the event.         * @return {Number}         */        getPageX : function(){            return this.xy[0];        },        /**         * 获取事件Y坐标。         * Gets the y coordinate of the event.         * @return {Number}         */        getPageY : function(){            return this.xy[1];        },        /**         * 获取事件的时间。         * Gets the time of the event.         * @return {Number}         */        getTime : function(){            if(this.browserEvent){                return E.getTime(this.browserEvent);            }            return null;        },                /**         * 获取事件的页面坐标。         * Gets the page coordinates of the event.         * @return {Array} xy值,格式[x, y]。The xy values like [x, y]         */        getXY : function(){            return this.xy;        },       /**         * 获取事件的目标对象。         * Gets the target for the event.         * @param {String} selector (可选的) 一个简易的选择符,用于筛选目标或查找目标的父级元素。(optional) A simple selector to filter the target or look for an ancestor of the target         * @param {Number/Mixed} maxDepth (可选的)搜索的最大深度(数字或是元素,默认为10||document.body)。(optional) The max depth to search as a number or element (defaults to 10 || document.body)         * @param {Boolean} returnEl (可选的) True表示为返回Ext.Element的对象而非DOM节点。(optional) True to return a Ext.Element object instead of DOM node         * @return {HTMLelement}         */        getTarget : function(selector, maxDepth, returnEl){            return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);        },        /**         * 获取相关的目标对象。         * Gets the related target.         * @return {HTMLElement}         */        getRelatedTarget : function(){            return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;        },        /**         * 常规化鼠标滚轮的有限增量(速度)。         * IE/Safari/Chrome/Opera中使用事件对象的wheelDelta属性,Firefox则使用detail属性。   属性的方向值也不一样,IE向前滚 > 0为120,相反在-120,Firefox向后滚 > 0为3,相反则-3。         * Normalizes mouse wheel delta across browsers         * @return {Number} The delta         */        getWheelDelta : function(){            var e = this.browserEvent;            var delta = 0;            if(e.wheelDelta){ /* IE/Opera. */                delta = e.wheelDelta/120;            }else if(e.detail){ /* Mozilla case. */                delta = -e.detail/3;            }            return delta;        },

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

?

下面看方法within

?

      within : function(el, related, allowEl){            if(el){                var t = this[related ? "getRelatedTarget" : "getTarget"]();                return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));            }            return false;        }

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

?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>Ext.EventObject.within method demo</title><meta http-equiv="content-type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css"href="../ext-3.3.1/resources/css/ext-all.css" /><style type="text/css">div {border: 1px solid blue;padding: 40px;margin: 10px;}</style><script type="text/javascript"src="../ext-3.3.1/adapter/ext/ext-base-debug.js"></script><script type="text/javascript"src="../ext-3.3.1/ext-all-debug-w-comments.js"></script><script type="text/javascript"src="../ext-3.3.1/src/locale/ext-lang-zh_CN.js"></script><script type="text/javascript" src="../ext-3.3.1/src/debug.js"></script><!-- 调试脚本 --><script type="text/javascript">Ext.onReady(function() {  Ext.BLANK_IMAGE_URL = '../ext-3.3.1/resources/images/default/s.gif';  Ext.QuickTips.init();        Ext.getBody().on('click', function(e){            if(e.within('some-el')){//如果该事件的目标对象是some-el的子元素,则返回true                alert('是在some-el的孩子节点上点击的!');            }else{            alert('你的点击不是some-el的孩子节点');            }        });        Ext.getBody().on('click', function(e,t){            if((t.id == 'some-el') && !e.within(t, true)){//如果allowEl设为true时,该事件的目标对象等于el也返回true                alert('直接在some-el上点击了鼠标!');                }            });  });</script></head><body><div id="some-el"><div id="some-el2">Ext.EventObject.within demo</div></div><br/><div id="some-el3"><div id="some-el4">不是some-el节点</div></div></body></html>
?

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

热点排行