jQuery.Event 包装事件对象

jQuery.Event 包装事件对象

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

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

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

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

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
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
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 Handling (事件处理)

 例子一:特定selector的点击

对class为“alert”的按钮点击将触发报警。

代码:

$(document).ready(function() {
  $('button.alert').click(function() {
   alert('欢迎光临61dh.com!');
  });
});
<button class="alert">特定点击</button>演示:特定点击

2.例子二:点击事件只发生1次
ID为“create-button”的链接被点击后,将在该链接后创建一个按钮,但是如果该按钮已经存在,将不再创建。

代码:

$('#create-button').click(function() {
  if ( $('button.new').length <1) { //根据需要这里可以设‘length’为不同的值
  $('<button class="new">刚创建的按钮</button>').insertAfter(this);
}
});
<button id="create-button">创建一个按钮</button>演示:创建一个按钮

3.例子三:事件的委派、传递

当列表里的一列被点击,新的列被加入列表。如果想让新加入的列也具有相同的事件控制,我们可以使用事件委派,把事件处理方法传递给新的列。

代码:

$(document).ready(function() {
  $('#list2').click(function(event) {//注意:这里加入了参数:event
  var $newLi = $('<li class="special"><button>新按钮</button></li>');
  var $tgt = $(event.target); //注意:这里用到target函数
  if ($tgt.is('button')) {
    $tgt.parent().after($newLi);
  }//这里用到,is()函数来判断当前点击元素的属性,如果是按钮就触发事件。
  });
});

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方法 如下

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对象。

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之七 及 各浏览器中鼠标按键值的差异 做了详细分析。

jquery event分析

*
 * author:prk
 * date:2008-08-17
 * comment:analyse of jquery event
 * 
 */
jQuery.event = {

    // add 事件到一个元素上。
    add : function(elem, types, handler, data) {
        if (elem.nodeType == 3 || elem.nodeType == 8)// 空白节点或注释
            return;

        // IE不能传入window,先复制一下。
        if (jQuery.browser.msie && elem.setInterval)
            elem = window;

        // 为handler分配一个全局唯一的Id
        if (!handler.guid)
            handler.guid = this.guid++;

        // 把data附到handler.data中
        if (data != undefined) {
            var fn = handler;
            handler = this.proxy(fn, function() {// 唯一Id,wrap原始handler Fn
                        return fn.apply(this, arguments);
                    });
            handler.data = data;
        }

        // 初始化元素的events。如果没有取到events中值,就初始化data: {}
        var events = jQuery.data(elem, "events")
                || jQuery.data(elem, "events", {}),
        // 如果没有取到handle中值,就初始化data: function() {....}
        handle = jQuery.data(elem, "handle")
                || jQuery.data(elem, "handle", function() {
                    // 处理一个触发器的第二个事件和当page已经unload之后调用一个事件。
                        if (typeof jQuery != "undefined"
                                && !jQuery.event.triggered)
                            return jQuery.event.handle.apply(// arguments.callee.elem=handle.elem
                                    arguments.callee.elem, arguments);
                    });
        // 增加elem做为handle属性,防止IE由于没有本地Event而内存泄露。
        handle.elem = elem;

        // 处理采用空格分隔多个事件名,如jQuery(...).bind("mouseo教程ver mouseout", fn);
        jQuery.each(types.split(/s+/), function(index, type) {
            // 命名空间的事件,一般不会用到。
                var parts = type.split(".");
                type = parts[0];
                handler.type = parts[1];

                // 捆绑到本元素type事件的所有处理函数
                var handlers = events[type];

                if (!handlers) {// 没有找到处理函数列表就初始化事件队列
                    handlers = events[type] = {};

                    // 如果type不是ready,或ready的setup执行返回false
                    if (!jQuery.event.special[type]
                            || jQuery.event.special[type].setup
                                    .call(elem, data) === false) {
                        // 调用系统的事件函数来注册事件
                        if (elem.addEventListener)// FF
                            elem.addEventListener(type, handle, false);
                        else if (elem.attachEvent)// IE
                            elem.attachEvent("on" + type, handle);
                    }
                }

                // 把处理器的id和handler形式属性对的形式保存在handlers列表中,
                // 也存在events[type][handler.guid]中。
                handlers[handler.guid] = handler;

                // 全局缓存这个事件的使用标识
                jQuery.event.global[type] = true;
            });

        // 防止IE内存泄露。
        elem = null;
    },

    guid : 1,
    global : {},

    // 从元素中remove一个事件
    remove : function(elem, types, handler) {
        if (elem.nodeType == 3 || elem.nodeType == 8)
            return;
        // 取出元素的events中Fn列表
        var events = jQuery.data(elem, "events"), ret, index;

        if (events) {
            // remove所有的该元素的事件 .是命名空间的处理
            if (types == undefined
                    || (typeof types == "string" && types.charAt(0) == "."))
                for (var type in events)
                    this.remove(elem, type + (types || ""));
            else {
                // types, handler参数采用{type:xxx,handler:yyy}形式
                if (types.type) {
                    handler = types.handler;
                    types = types.type;
                }

                // 处理采用空格分隔多个事件名 jQuery(...).unbind("mouseover mouseout", fn);
                jQuery
                        .each(types.split(/s+/), function(index, type) {
                            // 命名空间的事件,一般不会用到。
                                var parts = type.split(".");
                                type = parts[0];

                                if (events[type]) {// 事件名找到
                                    if (handler)// handler传入,就remove事件名的这个处理函数
                                        delete events[type][handler.guid];//guid的作用
                                    else    // remove这个事件的所有处理函数,带有命名空间的处理
                                        for (handler in events[type])
                                            if (!parts[1]
                                                    || events[type][handler].type == parts[1])
                                                delete events[type][handler];

                                    // 如果没有该事件的处理函数存在,就remove事件名
                                    for (ret in events[type])// 看看有没有?
                                        break;
                                    if (!ret) {// 没有
                                        if (!jQuery.event.special[type]//不是ready
                                                || jQuery.event.special[type].teardown
                                                        .call(elem) === false) {// type不等于ready
                                            if (elem.removeEventListener)// 在浏览器中remove事件名
                                                elem.removeEventListener(type,
                                                        jQuery.data(elem,
                                                                "handle"),
                                                        false);
                                            else if (elem.detachEvent)
                                                elem.detachEvent("on" + type,
                                                        jQuery.data(elem,
                                                                "handle"));
                                        }
                                        ret = null;
                                        delete events[type];// 在缓存中除去。
                                    }
                                }
                            });
            }

            // 不再使用,除去expando
            for (ret in events)
                break;
            if (!ret) {
                var handle = jQuery.data(elem, "handle");
                if (handle)
                    handle.elem = null;
                jQuery.removeData(elem, "events");
                jQuery.removeData(elem, "handle");
            }
        }
    },

    trigger : function(type, data, elem, donative, extra) {
        data = jQuery.makeArray(data);

        if (type.indexOf("!") >= 0) {// 支持!的not的操作如!click,除click之后的所有
            type = type.slice(0, -1);// 除最后一个字符?
            var exclusive = true;
        }

        if (!elem) {// 处理全局的fire事件
            if (this.global[type])
                jQuery.each(jQuery.cache, function() {
                    // 从cache中找到所有注册该事件的元素,触发改事件的处理函数
                        if (this.events && this.events[type])
                            jQuery.event.trigger(type, data, this.handle.elem);
                    });
        } else {// 处理单个元素事件的fire事件
            if (elem.nodeType == 3 || elem.nodeType == 8)
                return undefined;

            var val, ret, fn = jQuery.isFunction(elem[type] || null),
            // 我们是否要提交一个伪造的事件?
            event = !data[0] || !data[0].preventDefault;

            // 构建伪造的事件。
            if (event) {
                data.unshift( {//存到数组中的第一个
                    type : type,
                    target : elem,
                    preventDefault : function() {
                    },
                    stopPropagation : function() {
                    },
                    timeStamp : now()
                });
                data[0][expando] = true; // 不需要修正伪造事件
            }

            //防止事件名出错
            data[0].type = type;
            if (exclusive)
                data[0].exclusive = true;

            // 触发事件
            var handle = jQuery.data(elem, "handle");
            if (handle)
                val = handle.apply(elem, data);

            // Handle triggering native .onfoo handlers (and on links since we
            // don't call .click() for links)
            //处理触发.onfoo这样的本地处理方法,但是是对于links 's .click()不触发
            if ((!fn || (jQuery.nodeName(elem, 'a') && type == "click"))
                    && elem["on" + type]&& elem["on" + type].apply(elem, data) === false)
                val = false;

            // Extra functions don't get the custom event object
            if (event)
                data.shift();

            // 处理触发extra事件
            if (extra && jQuery.isFunction(extra)) {
                //执行extra,同时把结果存到data中。
                ret = extra.apply(elem, val == null ? data : data.concat(val));
                // if anything is returned, give it precedence and have it
                // overwrite the previous value
                if (ret !== undefined)
                    val = ret;
            }

            // 触发本地事件
            if (fn && donative !== false && val !== false
                    && !(jQuery.nodeName(elem, 'a') && type == "click")) {
                this.triggered = true;
                try {
                    elem[type]();
                    //对于一些hidden的元素,IE会报错
                } catch (e) {
                }
            }

            this.triggered = false;
        }

        return val;
    },

    handle : function(event) {
        // 返回 undefined or false
        var val, ret, namespace, all, handlers;

        event = arguments[0] = jQuery.event.fix(event || window.event);

        // 命名空间处理
        namespace = event.type.split(".");
        event.type = namespace[0];
        namespace = namespace[1];
        // all = true 表明任何 handler
        all = !namespace && !event.exclusive;
        // 找到元素的events中缓存的事件名的处理函数列表
        handlers = (jQuery.data(this, "events") || {})[event.type];

        for (var j in handlers) {// 每个处理函数执行
            var handler = handlers[j];

            // Filter the functions by class
            if (all || handler.type == namespace) {
                // 传入引用,为了之后删除它们
                event.handler = handler;
                event.data = handler.data;

                ret = handler.apply(this, arguments);// 执行事件处理函数

                if (val !== false)
                    val = ret;// 只要有一个处理函数返回false,本函数就返回false.

                if (ret === false) {// 不执行浏览器默认的动作
                    event.preventDefault();
                    event.stopPropagation();
                }
            }
        }

        return val;
    },

    props : "altKey attrChange attrName bubbles button cancelable charCode clientX "
            + "clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode "
            + "metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX "
            + "screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which"
                    .split(" "),

    //对事件进行包裹。
    fix : function(event) {
        if (event[expando] == true)//表明事件已经包裹过
            return event;

        //保存原始event,同时clone一个。
        var originalEvent = event;
        event = {
            originalEvent : originalEvent
        };

        for (var i = this.props.length, prop;i;) {
            prop = this.props[--i];
            event[prop] = originalEvent[prop];
        }
        
        event[expando] = true;
        
        //加上preventDefault and stopPropagation,在clone不会运行
        event.preventDefault = function() {
            // 在原始事件上运行
            if (originalEvent.preventDefault)
                originalEvent.preventDefault();
            
            originalEvent.returnValue = false;
        };
        event.stopPropagation = function() {
            // 在原始事件上运行
            if (originalEvent.stopPropagation)
                originalEvent.stopPropagation();
            
            originalEvent.cancelBubble = true;
        };

        // 修正 timeStamp
        event.timeStamp = event.timeStamp || now();

        // 修正target
        if (!event.target)
            event.target = event.srcElement || document;            
        if (event.target.nodeType == 3)//文本节点是父节点。
            event.target = event.target.parentNode;

        // relatedTarget
        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.clientLeft || 0);
            event.pageY = event.clientY
                    + (doc && doc.scrollTop || body && body.scrollTop || 0)
                    - (doc.clientTop || 0);
        }

        // Add which for key events
        if (!event.which
                && ((event.charCode || event.charCode === 0)
                        ? event.charCode
                        : event.keyCode))
            event.which = 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)
            event.which = (event.button & 1 ? 1 : (event.button & 2
                    ? 3
                    : (event.button & 4 ? 2 : 0)));

        return event;
    },

    proxy : function(fn, proxy) {
        // 作用就是分配全局guid.
        proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
        return proxy;
    },

    special : {
        ready : {
            // Make sure the ready event is setup
            setup : bindReady,
            teardown : function() {
            }
        }
    }
};

if (!jQuery.browser.msie) {
    // Checks if an event happened on an element within another element
    // Used in jQuery.event.special.mouseenter and mouseleave handlers
    var withinElement = function(event) {
        // Check if mouse(over|out) are still within the same parent element
        var parent = event.relatedTarget;
        // Traverse up the tree
        while (parent && parent != this)
            try {
                parent = parent.parentNode;
            } catch (e) {
                parent = this;
            }

        if (parent != this) {
            // set the correct event type
            event.type = event.data;
            // handle event if we actually just moused on to a non sub-element
            jQuery.event.handle.apply(this, arguments);
        }
    };

    jQuery.each( {
        mouseover : 'mouseenter',
        mouseout : 'mouseleave'
    }, function(orig, fix) {
        jQuery.event.special[fix] = {
            setup : function() {
                jQuery.event.add(this, orig, withinElement, fix);
            },
            teardown : function() {
                jQuery.event.remove(this, orig, withinElement);
            }
        };
    });
}

jQuery.fn.extend( {
    bind : function(type, data, fn) {
        return type == "unload" ? this.one(type, data, fn) : this
                .each(function() {// fn || data, fn && data实现了data参数可有可无
                    jQuery.event.add(this, type, fn || data, fn && data);
                });
    },

        // 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数。
        // 在每个对象上,这个事件处理函数只会被执行一次。其他规则与bind()函数相同。
        // 这个事件处理函数会接收到一个事件对象,可以通过它来阻止(浏览器)默认的行为。
        // 如果既想取消默认的行为,又想阻止事件起泡,这个事件处理函数必须返回false。
        one : function(type, data, fn) {
            var one = jQuery.event.proxy(fn || data, function(event) {
                jQuery(this).unbind(event, one);
                return (fn || data).apply(this, arguments);// this-->当前的元素
                });
            return this.each(function() {
                jQuery.event.add(this, type, one, fn && data);
            });
        },

        // bind()的反向操作,从每一个匹配的元素中删除绑定的事件。
        // 如果没有参数,则删除所有绑定的事件。
        // 你可以将你用bind()注册的自定义事件取消绑定。
        // I如果提供了事件类型作为参数,则只删除该类型的绑定事件。
        // 如果把在绑定时传递的处理函数作为第二个参数,则只有这个特定的事件处理函数会被删除。
        unbind : function(type, fn) {
            return this.each(function() {
                jQuery.event.remove(this, type, fn);
            });
        },

    
        trigger : function(type, data, fn) {
            return this.each(function() {
                jQuery.event.trigger(type, data, this, true, fn);
            });
        },
        //这个特别的方法将会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作.
        triggerHandler : function(type, data, fn) {
            return this[0]
                    && jQuery.event.trigger(type, data, this[0], false, fn);
        },
        
        //每次点击后依次调用函数。
        toggle : function(fn) {     
            var args = arguments, i = 1;
            
            while (i < args.length)//每个函数分配GUID
                jQuery.event.proxy(fn, args[i++]);

            return this.click(jQuery.event
                    .proxy(fn, function(event) {//分配GUID                    
                            this.lastToggle = (this.lastToggle || 0) % i;//上一个函数                            
                            event.preventDefault();//阻止缺省动作
                            //执行参数中的第几个函数,apply可以采用array-like的参数
                            //With apply, you can use an array literal, 
                            //for example, fun.apply(this, [name, value]),
                            //or an Array object, for example, fun.apply(this, new Array(name, value)). 
                            return args[this.lastToggle++].apply(this,
                                    arguments) || false;
                        }));
        },
        
        //一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法。
        //这是一个自定义的方法,它为频繁使用的任务提供了一种“保持在其中”的状态。
        //当鼠标移动到一个匹配的元素上面时,会触发指定的第一个函数。当鼠标移出这个元素时,
        //会触发指定的第二个函数。而且,会伴随着对鼠标是否仍然处在特定元素中的检测(例如,处在div中的图像),
        //如果是,则会继续保持“悬停”状态,而不触发移出事件(修正了使用mouseout事件的一个常见错误)。
        hover : function(fnOver, fnOut) {
            return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
        },
        
        //dom ready时执行 fn
        ready : function(fn) {          
            bindReady();//注册监听          
            if (jQuery.isReady)//ready就运行               
                fn.call(document, jQuery);          
            else
                // 增加这个函数到queue中。可见支持无数的ready的调用。
                jQuery.readyList.push(function() {
                    return fn.call(this, jQuery);
                });

            return this;
        }
    });

jQuery.extend( {
    isReady : false,
    readyList : [],
    // Handle when the DOM is ready
        ready : function() {            
            if (!jQuery.isReady) {      
                jQuery.isReady = true;
                
                if (jQuery.readyList) {                 
                    jQuery.each(jQuery.readyList, function() {
                        this.call(document);
                    });             
                    jQuery.readyList = null;
                }
                
                jQuery(document).triggerHandler("ready");
            }
        }
    });

var readyBound = false;

function bindReady() {
    if (readyBound)
        return;
    readyBound = true;

    // Mozilla, Opera, webkit nightlies 支持DOMContentLoaded事件    
    if (document.addEventListener && !jQuery.browser.opera)
        //当DOMContentLoaded事件触发时就运行jQuery.ready
        document.addEventListener("DOMContentLoaded", jQuery.ready, false);

    //IE或不是frame的window
    if (jQuery.browser.msie && window == top)
        (function() {
            if (jQuery.isReady)
                return;
            try {
                // 在ondocumentready之前,一直都会抛出异常              
                // http://网页特效.nwbox.com/IEContentLoaded/
                document.documentElement.doScroll("left");
            } catch (error) {
                //一直运行bindReady()(=arguments.callee)
                setTimeout(arguments.callee, 0);
                return;
            }           
            jQuery.ready();//documentready就运行jQuery.ready
        })();

    if (jQuery.browser.opera)
        document.addEventListener("DOMContentLoaded", function() {
            if (jQuery.isReady)
                return;
                //只有styleSheets完全enable时,才是完全的load,其实还有pic
            for (var i = 0;i < document.styleSheets.length; i++)
                if (document.styleSheets[i].disabled) {//通过styleSheets来判断
                    setTimeout(arguments.callee, 0);
                    return;
                }           
                jQuery.ready();
            }, false);

    if (jQuery.browser.safari) {
        var numStyles;
        (function() {
            if (jQuery.isReady)
                return;
                //首先得得到readyState=loaded或=complete
            if (document.readyState != "loaded"
                    && document.readyState != "complete") {
                setTimeout(arguments.callee, 0);
                return;
            }
            //取得style的length,比较它们之间的长度,看看是不是完成loaded
            if (numStyles === undefined)
                numStyles = jQuery("style, link[rel=stylesheet]").length;
            if (document.styleSheets.length != numStyles) {
                setTimeout(arguments.callee, 0);
                return;
            }           
            jQuery.ready();
        })();
    }

    //最后只能依赖于window.load.
    jQuery.event.add(window, "load", jQuery.ready);
}

//为jquery对象增加常用的事件方法
jQuery
        .each(
                ("blur,focus,load,resize,scroll,unload,click,dblclick,"
                        + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + "submit,keydown,keypress,keyup,error")
                        .split(","), function(i, name) {                    
                jQuery.fn[name] = function(fn) {
                    return fn ? this.bind(name, fn) : this.trigger(name);
                };
            });

// Prevent memory leaks in IE
// And prevent errors on refresh with events like mouseover in other browsers
// Window isn't included so as not to unbind existing unload events
jQuery(window).bind('unload', function() {
    for (var id in jQuery.cache)
        // Skip the window
        if (id != 1 && jQuery.cache[id].handle)
            jQuery.event.remove(jQuery.cache[id].handle.elem);
});

 

时间: 2024-09-11 08:12:15

jQuery.Event 包装事件对象的相关文章

浏览器-firefox event.target 事件对象获取不一致

问题描述 firefox event.target 事件对象获取不一致 jQuery(event.srcElement).parent() chrome下执行 firefox下执行是 源代码是这样的: 正常取得的对象是蓝色框中img,但是firefox中原对象是一个input ?.. 解决方案 firefox不支持srcElement吧这个是IE的,firefox的是target,而且注意事件对象的传递

js中获取事件对象的方法小结_javascript技巧

复制代码 代码如下: var evt = window.event || arguments[0]; 下面分三种添加事件的方式讨论,你也许会看到以前没有看到过的获取方式. 1,第一种添加事件的方式,直接在html的属性中写JS代码 复制代码 代码如下: <div onclick="alert(4);">Div1 Element</div> 大概这是上世纪90年代的写法,那时候直接把js代码写在网页中很普遍,也许那时候的js并不太重要,只是用来做做验证或一些花哨的

jQuery event事件对象用法浅析

最终传入事件处理程序的 event 其实已经被 jQuery 做过标准化处理, 其原有的事件对象则被保存于 event 对象的 originalEvent 属性之中, 每个 event 都是 jQuery.Event 的实例,其原型链中保存有六个方法,  代码如下 复制代码 jQuery.Event.prototype = {     preventDefault: function() {         // 取消事件默认行为     },     stopPropagation: func

从零开始学习jQuery (五) 事件与事件对象

一.摘要 事件是脚本编程的灵魂. 所以本章内容也是jQuery学习的重点. 本文将对jQuery中的事件处理以及事件对象进行详细的讲解. 二.前言 本篇文章是至今为止本系列内容最多的一篇, 足以可见其重要性.大家反映要多列举示例. 我会在时间允许的情况下尽量多列举示例. 真正的投入生产使用的实例暂时还无法加入到文章中, 但是可能最后我会列举一些作品供大家借鉴. 另外本人水平有限, 因为我不是UI设计师. 文章可能有错误的地方, 希望大家帮忙指出, 一起学习一起进步. 在技术的世界里我们是没有任何

jQuery中事件对象e的事件冒泡用法

 e.stopPropagation()阻止事件冒泡  代码如下: <head>  <title></title>  <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>  </head>  <body>  <table>  <tr>  <td><span

从零开始学习jQuery (五) jquery事件与事件对象_jquery

一.摘要 事件是脚本编程的灵魂. 所以本章内容也是jQuery学习的重点. 本文将对jQuery中的事件处理以及事件对象进行详细的讲解.  二.前言 本篇文章是至今为止本系列内容最多的一篇, 足以可见其重要性.  大家反映要多列举示例. 我会在时间允许的情况下尽量多列举示例. 真正的投入生产使用的实例暂时还无法加入到文章中, 但是可能最后我会列举一些作品供大家借鉴. 另外本人水平有限, 因为我不是UI设计师. 文章可能有错误的地方, 希望大家帮忙指出, 一起学习一起进步. 在技术的世界里我们是没

jQuery中事件对象e的事件冒泡用法示例介绍_jquery

之前查手册的时候没有看到有事件对象这一概念,当时我想实现的是点击一个文本框出现一个下拉多选框,在文本框失去焦点是触发blur事件,从而使下拉框隐藏起来.但是当我要选择多选框是也会使它隐藏,就不能进行选择了,这让我很郁闷.查了一天的资料,终于在脱离了焦点这一块.在网上发现有一个事件冒泡的东西,发现通过点击可以实现我的这一功能. e.stopPropagation()阻止事件冒泡 复制代码 代码如下: <head> <title></title> <script sr

jQuery事件对象总结_jquery

 本人对jquery的event不懂,搜索了很多关于jquery event事件介绍,下面我来记录一下,有需要了解jquery event事件用法的朋友可参考.希望此文章对各位有所帮助. 学习要点: 事件对象 冒泡和阻止默认行为 一.事件对象 在JS中,我们已经详细讨论了JS的事件对象,这里就挑几个常用的探讨 <code class=" hljs xml"></code><div><code class=" hljs xml"

jquery 事件对象属性小结_jquery

使用事件自然少不了事件对象.  因为不同浏览器之间事件对象的获取, 以及事件对象的属性都有差异, 导致我们很难跨浏览器使用事件对象. jQuery中统一了事件对象,  当绑定事件处理函数时,  会将jQuery格式化后的事件对象作为唯一参数传入: $("#testDiv").bind("click", function(event) { }); 关于event对象的详细说明, 可以参考jQuery官方文档: http://docs.jquery.com/Events