zoukankan      html  css  js  c++  java
  • 读jQuery之八(包装事件对象)

    http://www.cnblogs.com/snandy/archive/2011/06/17/2081213.html

    由于各个浏览器中原生事件对象的 差异性 ,多数 JS库/框架 都或多或少的对原生事件对象进行了修复及包装。


    比如,停止事件冒泡IE用 cancelBubble ,标准浏览器则用 stopPropagation 。

    获取事件源对象,IE用 srcElement ,标准浏览器则用 target 诸如此类。

     jQuery 对原生事件对象的修复和包装主要使用 jQuery.Event 类和 jQuery.event.fix 方法。

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    jQuery.Event = function( src ) {
        // Allow instantiation without the 'new' keyword
        if ( !this.preventDefault ) {
            return new jQuery.Event( src );
        }
     
        // Event object
        if ( src && src.type ) {
            this.originalEvent = src;
            this.type = src.type;
     
            // Events bubbling up the document may have been marked as prevented
            // by a handler lower down the tree; reflect the correct value.
            this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
                src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
     
        // Event type
        } else {
            this.type = src;
        }
     
        // timeStamp is buggy for some events on Firefox(#3843)
        // So we won't rely on the native value
        this.timeStamp = jQuery.now();
     
        // Mark it as fixed
        this[ jQuery.expando ] = true;
    };
     
    function returnFalse() {
        return false;
    }
    function returnTrue() {
        return true;
    }
     
    // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
    jQuery.Event.prototype = {
        preventDefault: function() {
            this.isDefaultPrevented = returnTrue;
     
            var e = this.originalEvent;
            if ( !e ) {
                return;
            }
     
            // if preventDefault exists run it on the original event
            if ( e.preventDefault ) {
                e.preventDefault();
     
            // otherwise set the returnValue property of the original event to false (IE)
            } else {
                e.returnValue = false;
            }
        },
        stopPropagation: function() {
            this.isPropagationStopped = returnTrue;
     
            var e = this.originalEvent;
            if ( !e ) {
                return;
            }
            // if stopPropagation exists run it on the original event
            if ( e.stopPropagation ) {
                e.stopPropagation();
            }
            // otherwise set the cancelBubble property of the original event to true (IE)
            e.cancelBubble = true;
        },
        stopImmediatePropagation: function() {
            this.isImmediatePropagationStopped = returnTrue;
            this.stopPropagation();
        },
        isDefaultPrevented: returnFalse,
        isPropagationStopped: returnFalse,
        isImmediatePropagationStopped: returnFalse
    };

    jQuery.Event 类主要做了以下工作

    1. 扩充了 originalEvent 属性,该属性暂存了原生事件对象
    2. 修复了 timeStamp ,该属性IE6/7/8不支持,其它支持的各个浏览器中返回值也不同
    3. 阻止DOM元素默认行为统一采用 preventDefault
    4. 停止事件冒泡统一采用 stopPropagation
    5. 实现或扩充了 DOM3事件 的几个方法:stopImmediatePropagation、isDefaultPrevented、isPropagationStopped、isImmediatePropagationStopped


    此外,jQuery.Event的 写类方式 也较独特。它 使用隐藏的new创建对象 。

    jQuery.event.fix方法 如下

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    fix: function( event ) {
        if ( event[ jQuery.expando ] ) {
            return event;
        }
     
        // store a copy of the original event object
        // and "clone" to set read-only properties
        var originalEvent = event;
        event = jQuery.Event( originalEvent );
     
        for ( var i = this.props.length, prop; i; ) {
            prop = this.props[ --i ];
            event[ prop ] = originalEvent[ prop ];
        }
     
        // Fix target property, if necessary
        if ( !event.target ) {
            // Fixes #1925 where srcElement might not be defined either
            event.target = event.srcElement || document;
        }
     
        // check if target is a textnode (safari)
        if ( event.target.nodeType === 3 ) {
            event.target = event.target.parentNode;
        }
     
        // Add relatedTarget, if necessary
        if ( !event.relatedTarget && event.fromElement ) {
            event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
        }
     
        // Calculate pageX/Y if missing and clientX/Y available
        if ( event.pageX == null && event.clientX != null ) {
            var doc = document.documentElement,
                body = document.body;
     
            event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
            event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
        }
     
        // Add which for key events
        if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
            event.which = event.charCode != null ? event.charCode : event.keyCode;
        }
     
        // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
        if ( !event.metaKey && event.ctrlKey ) {
            event.metaKey = event.ctrlKey;
        }
     
        // Add which for click: 1 === left; 2 === middle; 3 === right
        // Note: button is not normalized, so don't use it
        if ( !event.which && event.button !== undefined ) {
            event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
        }
     
        return event;
    },

    它主要做了以下工作
    1,event = jQuery.Event( originalEvent ); 该句创建了一个jQuery.Event类的实例对象,该对象修复及扩充上面刚刚提到了。
    2, 一个循环将原生事件对象的所有属性拷贝给 1 中的event对象。

    1
    2
    3
    4
    for ( var i = this.props.length, prop; i; ) {
        prop = this.props[ --i ];
        event[ prop ] = originalEvent[ prop ];
    }

    3, 统一事件源对象为 target 。
    4, 统一事件相关对象为 relativeTarget 。
    5, 扩充了pageX , pageY ,这两个属性首次在Firefox中引入的。不支持该属性的浏览器使用clientX/Y计算得到。
    6, 扩充了 which ,使用它获取键盘按键值(keyCode)。这个属性也是在Firefox引入的。
    7, 修复了metaKey。
    8, 扩充了which,使用它获取鼠标按键值

    细心的人可能注意到了,jQuery获取键盘按键值和鼠标按键值都是采用which。它没有向其它属性一样去兼容W3C已有标准 (button )。这一点我在 读jQuery之七 及 各浏览器中鼠标按键值的差异 做了详细分析。

  • 相关阅读:
    腾讯云大数据套件Hermes-MR索引插件使用总结
    【文智背后的奥秘】系列篇——文本聚类系统
    【文智背后的奥秘】系列篇——关键词智能提取
    微信Tinker的一切都在这里,包括源码(一)
    腾讯云CMQ消息队列在Windows环境下的使用
    树莓派使用modbus与stm32通信
    Ubuntu manjaro 17.10 UTC
    如何彻底禁止360浏览器弹窗
    CentOS DesktopEntry
    centos7 安装qt
  • 原文地址:https://www.cnblogs.com/lbangel/p/3097244.html
Copyright © 2011-2022 走看看