读Ext之八(原生事件对象的修复及扩充)
Ext库也对浏览器原生的事件对象做了包装,以保证兼容所有浏览器。
这里 列举了浏览器原生事件对象各浏览器中兼容性,这里 列出了各种情况下事件对象的获取。
在Ext事件管理类 Ext.EventManager 中会悄悄的将浏览器原始事件对象进行转换
1 | e = Ext.EventObject.setEvent(e); |
Ext.EventObject 即为包装后的事件对象(暂称为Ext事件对象)。先从全局上看看该对象的实现,其中...省略了部分代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Ext.EventObject = function (){ var E = Ext.lib.Event, ...; Ext.EventObjectImpl = function (e){ if (e){ this .setEvent(e.browserEvent || e); } }; Ext.EventObjectImpl.prototype = { /** @private */ setEvent : function (e){ var me = this ; ... }, ... }; return new Ext.EventObjectImpl(); }(); |
可看到匿名函数执行后返回了Ext.EventObjectImpl的实例对象,该对象才是真正的Ext.EventObject。
这一点和jQuery类似,jQuery中是new了一个Event类。
第一句
1 | var E = Ext.lib.Event, |
变量E暂存了Ext.lib.Event对象,该对象在 读Ext之四 中已经介绍了。后面的很多方法都要用 E 来实现。
第二个变量 safariKeys 为一个对象,
1 2 3 4 5 6 7 8 9 10 11 12 13 | // safari keypress events for special keys return bad keycodes safariKeys = { 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中keypress事件返回错误的键码。但我用Safari 5.0.3测试input,document.body 。
回车键(enter)返回的是13,正确的。方向键(left等)和翻页键(page up等)则不会触发。
测试代码如下
1 2 3 4 5 6 7 8 9 | var inp = document.getElementById( 'txt' ); inp.onkeypress = function (e){ e = window.event || e; alert(e.keyCode); } document.body.onkeypress = function (e){ e = window.event || e; alert(e.keyCode); } |
之前已经提到过要获取按键值应该使用keydown或keyup事件。这里应该是为了兼容旧版本的Safari。
第三个变量是btnMap
1 2 3 | // normalize button clicks btnMap = Ext.isIE ? {1:0,4:1,2:2} : (Ext.isWebKit ? {1:0,2:1,3:2} : {0:0,1:1,2:2}); |
用来统一鼠标按键值。这里 有详细分析,不重复了。经测试,webkit内核的Safari5和Chrome7在mousedown/mouseup事件中左,中,右键返回的是符合标准的0,1,2。因此这里对webkit的判断是可去掉的。
接下来是 Ext.EventObjectImpl 类的定义
1 2 3 4 5 | Ext.EventObjectImpl = function (e){ if (e){ this .setEvent(e.browserEvent || e); } }; |
如果传了浏览器原生事件对象,则调用this.setEvent,this.setEvent是挂在Ext.EventObjectImpl的原型上的。原型上还有很多其它方法,逐个看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | setEvent : function (e){ var me = this ; if (e == me || (e && e.browserEvent)){ // already wrapped return e; } me.browserEvent = e; if (e){ // normalize buttons me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1); if (e.type == 'click' && 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; // 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 me.target = E.getTarget(e); // same for XY me.xy = E.getXY(e); } 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; }, |
1 | var me = this ; |
将this暂存到me上。接着判断所传的是否就是本身,如果是则不再包装直接返回。仅当是浏览器原生事件对象才进行包装。
1 | me.browserEvent = e; |
把浏览器原始事件对象挂在this上,即该类的字段browserEvent就是浏览器原始对象。因为有时会用到浏览器原始对象。
1 | me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1); |
先从btnMap中取,上面已经提到了。e.which原本是键盘事件,jQuery中将鼠标按键也存在e.which中,Ext这里是为了兼容jQuery。
1 2 3 | if (e.type == 'click' && me.button == -1){ me.button = 0; } |
建议获取判断鼠标按下哪个键应该使用mousedown/mouseup事件,这里是为了兼容click事件。但有点问题,IE6/7/8中左键单击(click)事件为0,但中键和右键单击(click)则无法触发该事件。这里的实现欠妥。
1 2 | me.type = e.type; me.shiftKey = e.shiftKey; |
事件类型(如click)和shiftKey复制到this上。
接着是ctrlKey,altKey,keyCode,charCode。
接着是target,使用E.getTarget(e)获取。E.getTarget在第四篇提到了。
接着是xy,xy不是事件对象原有的属性。而是Ext自定义的。
setEvent说了,看stopEvent
1 2 3 4 5 6 7 8 9 | stopEvent : function (){ var me = this ; if (me.browserEvent){ if (me.browserEvent.type == 'mousedown' ){ Ext.EventManager.stoppedMouseDownEvent.fire(me); } E.stopEvent(me.browserEvent); } }, |
用来停止事件冒泡,阻止元素默认行为。
有两点,其一对mousedown事件做了特殊处理Ext.EventManager.stoppedMouseDownEvent 实际是Ext.util.Event类的一个实例对象。如
1 | pub.stoppedMouseDownEvent = new Ext.util.Event(); |
后续有一篇会读到该类。
其二,调用了E.stopEvent(me.browserEvent),这里的E即为Ext.lib.Event对象,第四篇提到了。接着是preventDefault,stopPropagation等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | preventDefault : function (){ if ( this .browserEvent){ E.preventDefault( this .browserEvent); } }, stopPropagation : function (){ var me = this ; if (me.browserEvent){ if (me.browserEvent.type == 'mousedown' ){ Ext.EventManager.stoppedMouseDownEvent.fire(me); } E.stopPropagation(me.browserEvent); } }, |
可看到都是调用E(Ext.lib.Event)来实现的,不再重复。
getTarget 采用事件代理时会用到,实现上用到了Ext.fly等,后续提到。getWheelDelta 用来获取滚轮的速度
1 2 3 4 5 6 7 8 9 10 | 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; }, |
IE/Safari/Chrome/Opera中使用事件对象的wheelDelta属性,Firefox则使用detail属性。
属性的方向值也不一样,IE向前滚 > 0为120,相反在-120,Firefox向后滚 > 0为3,相反则-3。
好了,整个Ext事件对象读完了。可以看到Ext为了保证兼容,统一对原生事件对象做了修复,扩充等。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端