5-10 重写事件对象
本节编程练习不计算学习进度,请电脑登录imooc.com操作

重写事件对象

jQuery 为 dom 处理而生,那么处理兼容的手段自然是独树一帜了,所以:

jQuery对事件的对象的兼容问题单独抽象出一个 fix 类,用来重写这个事件对象

jQuery 利用 jQuery.event.fix() 来解决跨浏览器的兼容性问题,统一接口。

除该核心方法外,我们要根据事件的类型,统一接口的获取,所以 jQuery 引入了 (jQuery.event) props、 fixHooks、keyHooks、mouseHooks 等数据模块。

  1. props 存储了原生事件对象 event 的通用属性
  2. keyHook.props 存储键盘事件的特有属性
  3. mouseHooks.props 存储鼠标事件的特有属性。
  4. keyHooks.filter 和 mouseHooks.filter 两个方法分别用于修改键盘和鼠标事件的属性兼容性问题,用于统一接口。
  5. 比如 event.which 通过 event.charCode 或 event.keyCode 或 event.button 来标准化。

最后 fixHooks 对象用于缓存不同事件所属的事件类别,比如:

fixHooks['click'] === jQuery.event.mouseHooks;
fixHooks['keydown'] === jQuery.event.keyHooks;
fixHooks['focusin'] === {};

从源码处获取对事件对象的操作,通过调用 jQuery.Event 重写事件对象,将浏览器原生 Event 的属性赋值到新创建的 jQuery.Event 对象中去。

event = new jQuery.Event( originalEvent );

event 就是对原生事件对象的一个重写了,为什么要这样,jQuery要增加自己的处理机制呗,这样更灵活,而且还可以传递 data 数据,也就是用户自定义的数据。

构造出来的新对象:

 

看图,通过 jQuery.Event 构造器,仅仅只有一些定义的属性与方法,但是原生的事件对象的属性是不是丢了?

所以还需要把原生的的属性给混入到这个新对象上,那么此时带来一个问题,不同事件会产生了不同的事件对象,拥有不同的属性,所以还有一套适配的机制,根据不同的触发点去适配需要混入的属性名。

扩展通过 jQuery.Event 构造出的新事件对象属性

//扩展事件属性
this.fixHooks[ type ] = fixHook =
    rmouseEvent.test( type ) ? this.mouseHooks :
        rkeyEvent.test( type ) ? this.keyHooks :
        {};

有一些属性是共用的,都存在,所以单独拿出来就好了。

props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),

然后把私有的与公共的拼接一下。

copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;

然后混入到这个新的对象上。

jQuery 自己写了一个基于 native event 的 Event 对象,并且把 copy 数组中对应的属性从 native event 中复制到自己的 Event 对象中。

while ( i-- ) {
    prop = copy[ i ];
    event[ prop ] = originalEvent[ prop ];
}

在最后 jQuery 还不忘放一个钩子,调用 fixHook.fitler 方法用以纠正一些特定的 event 属性。例如 mouse event 中的 pageX,pageY,keyboard event中的 which,进一步修正事件对象属性的兼容问题。

fixHook.filter? fixHook.filter( event, originalEvent ) : event

fixHook 就是在上一章,预处理的时候用到的,分解 type 存进去的,针对这个特性的单独处理,最后返回这个“全新的”Event 对象。

总的来说 jQuery.event.fix 做的事情:

1.将原生的事件对象 event 修正为一个新的可写 event 对象,并对该 event 的属性以及方法统一接口
2.该方法在内部调用了 jQuery.Event(event) 构造函数

任务

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. <script src="http://www.imooc.com/static/lib/jquery/1.9.1/jquery.js" type="text/javascript"></script>
  6. <title>重写事件对象</title>
  7. </head>
  8. <body>
  9.  
  10.  
  11. <div id="aaron">
  12. <div>
  13. <p>点击重写事件对象</p>
  14. </div>
  15. </div>
  16. <ul></ul>
  17.  
  18. <script type="text/javascript">
  19.  
  20.  
  21. function returnTrue() {
  22. return true;
  23. }
  24.  
  25. function returnFalse() {
  26. return false;
  27. }
  28.  
  29.  
  30. //模拟出事件对象
  31. //增加调用判断方法
  32. var Event = function(src, props) {
  33. if (src && src.type) {
  34. this.originalEvent = src;
  35. this.type = src.type;
  36. this.isDefaultPrevented = src.defaultPrevented ||
  37. src.defaultPrevented === undefined &&
  38. src.returnValue === false ?
  39. returnTrue :
  40. returnFalse;
  41. } else {
  42. this.type = src;
  43. }
  44. this.timeStamp = src && src.timeStamp || jQuery.now();
  45. this[jQuery.expando] = true;
  46. };
  47.  
  48. Event.prototype = {
  49. isDefaultPrevented: returnFalse,
  50. isPropagationStopped: returnFalse,
  51. isImmediatePropagationStopped: returnFalse,
  52. preventDefault: function() {
  53. var e = this.originalEvent;
  54. this.isDefaultPrevented = returnTrue;
  55. if (e && e.preventDefault) {
  56. e.preventDefault();
  57. }
  58. },
  59. stopPropagation: function() {
  60. var e = this.originalEvent;
  61. this.isPropagationStopped = returnTrue;
  62. if (e && e.stopPropagation) {
  63. e.stopPropagation();
  64. }
  65. },
  66. stopImmediatePropagation: function() {
  67. var e = this.originalEvent;
  68. this.isImmediatePropagationStopped = returnTrue;
  69. if (e && e.stopImmediatePropagation) {
  70. e.stopImmediatePropagation();
  71. }
  72. this.stopPropagation();
  73. }
  74. };
  75.  
  76. function fix(event) {
  77. //原始事件引用
  78. var originalEvent = event;
  79. //鼠标事件对象的属性
  80. var props = "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" ");
  81.  
  82. //创建事件对象
  83. var event = new Event(originalEvent);
  84.  
  85. //混入事件属性
  86. i = props.length;
  87. while (i--) {
  88. prop = props[i];
  89. event[prop] = originalEvent[prop];
  90. }
  91. return event
  92. }
  93.  
  94.  
  95. document.getElementById('aaron').addEventListener('click',function(e){
  96. e = fix(e)
  97. for(var i in e){
  98. show('属性'+i+' 值:' +e[i])
  99. }
  100. },false)
  101.  
  102.  
  103.  
  104. function show(data) {
  105. $('ul').append('<li>' + data + '</li>')
  106. }
  107.  
  108. </script>
  109.  
  110. </body>
  111. </html>
下一节