Event 系列: jquery event 源码

  1. /*  
  2.  * author:prk  
  3.  * date:2008-08-17  
  4.  * comment:analyse of jquery event  
  5.  *   
  6.  */  
  7. jQuery.event = {   
  8.   
  9.     // add 事件到一个元素上。   
  10.     add : function(elem, types, handler, data) {   
  11.         if (elem.nodeType == 3 || elem.nodeType == 8)// 空白节点或注释   
  12.             return;   
  13.   
  14.         // IE不能传入window,先复制一下。   
  15.         if (jQuery.browser.msie && elem.setInterval)   
  16.             elem = window;   
  17.   
  18.         // 为handler分配一个全局唯一的Id   
  19.         if (!handler.guid)   
  20.             handler.guid = this.guid++;   
  21.   
  22.         // 把data附到handler.data中   
  23.         if (data != undefined) {   
  24.             var fn = handler;   
  25.             handler = this.proxy(fn, function() {// 唯一Id,wrap原始handler Fn   
  26.                         return fn.apply(this, arguments);   
  27.                     });   
  28.             handler.data = data;   
  29.         }   
  30.   
  31.         // 初始化元素的events。如果没有取到events中值,就初始化data: {}   
  32.         var events = jQuery.data(elem, "events")   
  33.                 || jQuery.data(elem, "events", {}),   
  34.         // 如果没有取到handle中值,就初始化data: function() {....}   
  35.         handle = jQuery.data(elem, "handle")   
  36.                 || jQuery.data(elem, "handle", function() {   
  37.                     // 处理一个触发器的第二个事件和当page已经unload之后调用一个事件。   
  38.                         if (typeof jQuery != "undefined"  
  39.                                 && !jQuery.event.triggered)   
  40.                             return jQuery.event.handle.apply(// arguments.callee.elem=handle.elem   
  41.                                     arguments.callee.elem, arguments);   
  42.                     });   
  43.         // 增加elem做为handle属性,防止IE由于没有本地Event而内存泄露。   
  44.         handle.elem = elem;   
  45.   
  46.         // 处理采用空格分隔多个事件名,如jQuery(...).bind("mouseover mouseout", fn);   
  47.         jQuery.each(types.split(/\s+/), function(index, type) {   
  48.             // 命名空间的事件,一般不会用到。   
  49.                 var parts = type.split(".");   
  50.                 type = parts[0];   
  51.                 handler.type = parts[1];   
  52.   
  53.                 // 捆绑到本元素type事件的所有处理函数   
  54.                 var handlers = events[type];   
  55.   
  56.                 if (!handlers) {// 没有找到处理函数列表就初始化事件队列   
  57.                     handlers = events[type] = {};   
  58.   
  59.                     // 如果type不是ready,或ready的setup执行返回false   
  60.                     if (!jQuery.event.special[type]   
  61.                             || jQuery.event.special[type].setup   
  62.                                     .call(elem, data) === false) {   
  63.                         // 调用系统的事件函数来注册事件   
  64.                         if (elem.addEventListener)// FF   
  65.                             elem.addEventListener(type, handle, false);   
  66.                         else if (elem.attachEvent)// IE   
  67.                             elem.attachEvent("on" + type, handle);   
  68.                     }   
  69.                 }   
  70.   
  71.                 // 把处理器的id和handler形式属性对的形式保存在handlers列表中,   
  72.                 // 也存在events[type][handler.guid]中。   
  73.                 handlers[handler.guid] = handler;   
  74.   
  75.                 // 全局缓存这个事件的使用标识   
  76.                 jQuery.event.global[type] = true;   
  77.             });   
  78.   
  79.         // 防止IE内存泄露。   
  80.         elem = null;   
  81.     },   
  82.   
  83.     guid : 1,   
  84.     global : {},   
  85.   
  86.     // 从元素中remove一个事件   
  87.     remove : function(elem, types, handler) {   
  88.         if (elem.nodeType == 3 || elem.nodeType == 8)   
  89.             return;   
  90.         // 取出元素的events中Fn列表   
  91.         var events = jQuery.data(elem, "events"), ret, index;   
  92.   
  93.         if (events) {   
  94.             // remove所有的该元素的事件 .是命名空间的处理   
  95.             if (types == undefined   
  96.                     || (typeof types == "string" && types.charAt(0) == "."))   
  97.                 for (var type in events)   
  98.                     this.remove(elem, type + (types || ""));   
  99.             else {   
  100.                 // types, handler参数采用{type:xxx,handler:yyy}形式   
  101.                 if (types.type) {   
  102.                     handler = types.handler;   
  103.                     types = types.type;   
  104.                 }   
  105.   
  106.                 // 处理采用空格分隔多个事件名 jQuery(...).unbind("mouseover mouseout", fn);   
  107.                 jQuery   
  108.                         .each(types.split(/\s+/), function(index, type) {   
  109.                             // 命名空间的事件,一般不会用到。   
  110.                                 var parts = type.split(".");   
  111.                                 type = parts[0];   
  112.   
  113.                                 if (events[type]) {// 事件名找到   
  114.                                     if (handler)// handler传入,就remove事件名的这个处理函数   
  115.                                         delete events[type][handler.guid];//guid的作用   
  116.                                     else    // remove这个事件的所有处理函数,带有命名空间的处理   
  117.                                         for (handler in events[type])   
  118.                                             if (!parts[1]   
  119.                                                     || events[type][handler].type == parts[1])   
  120.                                                 delete events[type][handler];   
  121.   
  122.                                     // 如果没有该事件的处理函数存在,就remove事件名   
  123.                                     for (ret in events[type])// 看看有没有?   
  124.                                         break;   
  125.                                     if (!ret) {// 没有   
  126.                                         if (!jQuery.event.special[type]//不是ready   
  127.                                                 || jQuery.event.special[type].teardown   
  128.                                                         .call(elem) === false) {// type不等于ready   
  129.                                             if (elem.removeEventListener)// 在浏览器中remove事件名   
  130.                                                 elem.removeEventListener(type,   
  131.                                                         jQuery.data(elem,   
  132.                                                                 "handle"),   
  133.                                                         false);   
  134.                                             else if (elem.detachEvent)   
  135.                                                 elem.detachEvent("on" + type,   
  136.                                                         jQuery.data(elem,   
  137.                                                                 "handle"));   
  138.                                         }   
  139.                                         ret = null;   
  140.                                         delete events[type];// 在缓存中除去。   
  141.                                     }   
  142.                                 }   
  143.                             });   
  144.             }   
  145.   
  146.             // 不再使用,除去expando   
  147.             for (ret in events)   
  148.                 break;   
  149.             if (!ret) {   
  150.                 var handle = jQuery.data(elem, "handle");   
  151.                 if (handle)   
  152.                     handle.elem = null;   
  153.                 jQuery.removeData(elem, "events");   
  154.                 jQuery.removeData(elem, "handle");   
  155.             }   
  156.         }   
  157.     },   
  158.   
  159.     trigger : function(type, data, elem, donative, extra) {   
  160.         data = jQuery.makeArray(data);   
  161.   
  162.         if (type.indexOf("!") >= 0) {// 支持!的not的操作如!click,除click之后的所有   
  163.             type = type.slice(0, -1);// 除最后一个字符?   
  164.             var exclusive = true;   
  165.         }   
  166.   
  167.         if (!elem) {// 处理全局的fire事件   
  168.             if (this.global[type])   
  169.                 jQuery.each(jQuery.cache, function() {   
  170.                     // 从cache中找到所有注册该事件的元素,触发改事件的处理函数   
  171.                         if (this.events && this.events[type])   
  172.                             jQuery.event.trigger(type, data, this.handle.elem);   
  173.                     });   
  174.         } else {// 处理单个元素事件的fire事件   
  175.             if (elem.nodeType == 3 || elem.nodeType == 8)   
  176.                 return undefined;   
  177.   
  178.             var val, ret, fn = jQuery.isFunction(elem[type] || null),   
  179.             // 我们是否要提交一个伪造的事件?   
  180.             event = !data[0] || !data[0].preventDefault;   
  181.   
  182.             // 构建伪造的事件。   
  183.             if (event) {   
  184.                 data.unshift( {//存到数组中的第一个   
  185.                     type : type,   
  186.                     target : elem,   
  187.                     preventDefault : function() {   
  188.                     },   
  189.                     stopPropagation : function() {   
  190.                     },   
  191.                     timeStamp : now()   
  192.                 });   
  193.                 data[0][expando] = true// 不需要修正伪造事件   
  194.             }   
  195.   
  196.             //防止事件名出错   
  197.             data[0].type = type;   
  198.             if (exclusive)   
  199.                 data[0].exclusive = true;   
  200.   
  201.             // 触发事件   
  202.             var handle = jQuery.data(elem, "handle");   
  203.             if (handle)   
  204.                 val = handle.apply(elem, data);   
  205.   
  206.             // Handle triggering native .onfoo handlers (and on links since we   
  207.             // don't call .click() for links)   
  208.             //处理触发.onfoo这样的本地处理方法,但是是对于links 's .click()不触发   
  209.             if ((!fn || (jQuery.nodeName(elem, 'a') && type == "click"))   
  210.                     && elem["on" + type]&& elem["on" + type].apply(elem, data) === false)   
  211.                 val = false;   
  212.   
  213.             // Extra functions don't get the custom event object   
  214.             if (event)   
  215.                 data.shift();   
  216.   
  217.             // 处理触发extra事件   
  218.             if (extra && jQuery.isFunction(extra)) {   
  219.                 //执行extra,同时把结果存到data中。   
  220.                 ret = extra.apply(elem, val == null ? data : data.concat(val));   
  221.                 // if anything is returned, give it precedence and have it   
  222.                 // overwrite the previous value   
  223.                 if (ret !== undefined)   
  224.                     val = ret;   
  225.             }   
  226.   
  227.             // 触发本地事件   
  228.             if (fn && donative !== false && val !== false  
  229.                     && !(jQuery.nodeName(elem, 'a') && type == "click")) {   
  230.                 this.triggered = true;   
  231.                 try {   
  232.                     elem[type]();   
  233.                     //对于一些hidden的元素,IE会报错   
  234.                 } catch (e) {   
  235.                 }   
  236.             }   
  237.   
  238.             this.triggered = false;   
  239.         }   
  240.   
  241.         return val;   
  242.     },   
  243.   
  244.     handle : function(event) {   
  245.         // 返回 undefined or false   
  246.         var val, ret, namespace, all, handlers;   
  247.   
  248.         event = arguments[0] = jQuery.event.fix(event || window.event);   
  249.   
  250.         // 命名空间处理   
  251.         namespace = event.type.split(".");   
  252.         event.type = namespace[0];   
  253.         namespace = namespace[1];   
  254.         // all = true 表明任何 handler   
  255.         all = !namespace && !event.exclusive;   
  256.         // 找到元素的events中缓存的事件名的处理函数列表   
  257.         handlers = (jQuery.data(this"events") || {})[event.type];   
  258.   
  259.         for (var j in handlers) {// 每个处理函数执行   
  260.             var handler = handlers[j];   
  261.   
  262.             // Filter the functions by class   
  263.             if (all || handler.type == namespace) {   
  264.                 // 传入引用,为了之后删除它们   
  265.                 event.handler = handler;   
  266.                 event.data = handler.data;   
  267.   
  268.                 ret = handler.apply(this, arguments);// 执行事件处理函数   
  269.   
  270.                 if (val !== false)   
  271.                     val = ret;// 只要有一个处理函数返回false,本函数就返回false.   
  272.   
  273.                 if (ret === false) {// 不执行浏览器默认的动作   
  274.                     event.preventDefault();   
  275.                     event.stopPropagation();   
  276.                 }   
  277.             }   
  278.         }   
  279.   
  280.         return val;   
  281.     },   
  282.   
  283.     props : "altKey attrChange attrName bubbles button cancelable charCode clientX "  
  284.             + "clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode "  
  285.             + "metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX "  
  286.             + "screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which"  
  287.                     .split(" "),   
  288.   
  289.     //对事件进行包裹。   
  290.     fix : function(event) {   
  291.         if (event[expando] == true)//表明事件已经包裹过   
  292.             return event;   
  293.   
  294.         //保存原始event,同时clone一个。   
  295.         var originalEvent = event;   
  296.         event = {   
  297.             originalEvent : originalEvent   
  298.         };   
  299.   
  300.         for (var i = this.props.length, prop;i;) {   
  301.             prop = this.props[--i];   
  302.             event[prop] = originalEvent[prop];   
  303.         }   
  304.            
  305.         event[expando] = true;   
  306.            
  307.         //加上preventDefault and stopPropagation,在clone不会运行   
  308.         event.preventDefault = function() {   
  309.             // 在原始事件上运行   
  310.             if (originalEvent.preventDefault)   
  311.                 originalEvent.preventDefault();   
  312.                
  313.             originalEvent.returnValue = false;   
  314.         };   
  315.         event.stopPropagation = function() {   
  316.             // 在原始事件上运行   
  317.             if (originalEvent.stopPropagation)   
  318.                 originalEvent.stopPropagation();   
  319.                
  320.             originalEvent.cancelBubble = true;   
  321.         };   
  322.   
  323.         // 修正 timeStamp   
  324.         event.timeStamp = event.timeStamp || now();   
  325.   
  326.         // 修正target   
  327.         if (!event.target)   
  328.             event.target = event.srcElement || document;               
  329.         if (event.target.nodeType == 3)//文本节点是父节点。   
  330.             event.target = event.target.parentNode;   
  331.   
  332.         // relatedTarget   
  333.         if (!event.relatedTarget && event.fromElement)   
  334.             event.relatedTarget = event.fromElement == event.target   
  335.                     ? event.toElement   
  336.                     : event.fromElement;   
  337.   
  338.         // Calculate pageX/Y if missing and clientX/Y available   
  339.         if (event.pageX == null && event.clientX != null) {   
  340.             var doc = document.documentElement, body = document.body;   
  341.             event.pageX = event.clientX   
  342.                     + (doc && doc.scrollLeft || body && body.scrollLeft || 0)   
  343.                     - (doc.clientLeft || 0);   
  344.             event.pageY = event.clientY   
  345.                     + (doc && doc.scrollTop || body && body.scrollTop || 0)   
  346.                     - (doc.clientTop || 0);   
  347.         }   
  348.   
  349.         // Add which for key events   
  350.         if (!event.which   
  351.                 && ((event.charCode || event.charCode === 0)   
  352.                         ? event.charCode   
  353.                         : event.keyCode))   
  354.             event.which = event.charCode || event.keyCode;   
  355.   
  356.         // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)   
  357.         if (!event.metaKey && event.ctrlKey)   
  358.             event.metaKey = event.ctrlKey;   
  359.   
  360.         // Add which for click: 1 == left; 2 == middle; 3 == right   
  361.         // Note: button is not normalized, so don't use it   
  362.         if (!event.which && event.button)   
  363.             event.which = (event.button & 1 ? 1 : (event.button & 2  
  364.                     ? 3  
  365.                     : (event.button & 4 ? 2 : 0)));   
  366.   
  367.         return event;   
  368.     },   
  369.   
  370.     proxy : function(fn, proxy) {   
  371.         // 作用就是分配全局guid.   
  372.         proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;   
  373.         return proxy;   
  374.     },   
  375.   
  376.     special : {   
  377.         ready : {   
  378.             // Make sure the ready event is setup   
  379.             setup : bindReady,   
  380.             teardown : function() {   
  381.             }   
  382.         }   
  383.     }   
  384. };   
  385.   
  386. if (!jQuery.browser.msie) {   
  387.     // Checks if an event happened on an element within another element   
  388.     // Used in jQuery.event.special.mouseenter and mouseleave handlers   
  389.     var withinElement = function(event) {   
  390.         // Check if mouse(over|out) are still within the same parent element   
  391.         var parent = event.relatedTarget;   
  392.         // Traverse up the tree   
  393.         while (parent && parent != this)   
  394.             try {   
  395.                 parent = parent.parentNode;   
  396.             } catch (e) {   
  397.                 parent = this;   
  398.             }   
  399.   
  400.         if (parent != this) {   
  401.             // set the correct event type   
  402.             event.type = event.data;   
  403.             // handle event if we actually just moused on to a non sub-element   
  404.             jQuery.event.handle.apply(this, arguments);   
  405.         }   
  406.     };   
  407.   
  408.     jQuery.each( {   
  409.         mouseover : 'mouseenter',   
  410.         mouseout : 'mouseleave'  
  411.     }, function(orig, fix) {   
  412.         jQuery.event.special[fix] = {   
  413.             setup : function() {   
  414.                 jQuery.event.add(this, orig, withinElement, fix);   
  415.             },   
  416.             teardown : function() {   
  417.                 jQuery.event.remove(this, orig, withinElement);   
  418.             }   
  419.         };   
  420.     });   
  421. }   
  422.   
  423. jQuery.fn.extend( {   
  424.     bind : function(type, data, fn) {   
  425.         return type == "unload" ? this.one(type, data, fn) : this  
  426.                 .each(function() {// fn || data, fn && data实现了data参数可有可无   
  427.                     jQuery.event.add(this, type, fn || data, fn && data);   
  428.                 });   
  429.     },   
  430.   
  431.         // 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数。   
  432.         // 在每个对象上,这个事件处理函数只会被执行一次。其他规则与bind()函数相同。   
  433.         // 这个事件处理函数会接收到一个事件对象,可以通过它来阻止(浏览器)默认的行为。   
  434.         // 如果既想取消默认的行为,又想阻止事件起泡,这个事件处理函数必须返回false。   
  435.         one : function(type, data, fn) {   
  436.             var one = jQuery.event.proxy(fn || data, function(event) {   
  437.                 jQuery(this).unbind(event, one);   
  438.                 return (fn || data).apply(this, arguments);// this-->当前的元素   
  439.                 });   
  440.             return this.each(function() {   
  441.                 jQuery.event.add(this, type, one, fn && data);   
  442.             });   
  443.         },   
  444.   
  445.         // bind()的反向操作,从每一个匹配的元素中删除绑定的事件。   
  446.         // 如果没有参数,则删除所有绑定的事件。   
  447.         // 你可以将你用bind()注册的自定义事件取消绑定。   
  448.         // I如果提供了事件类型作为参数,则只删除该类型的绑定事件。   
  449.         // 如果把在绑定时传递的处理函数作为第二个参数,则只有这个特定的事件处理函数会被删除。   
  450.         unbind : function(type, fn) {   
  451.             return this.each(function() {   
  452.                 jQuery.event.remove(this, type, fn);   
  453.             });   
  454.         },   
  455.   
  456.        
  457.         trigger : function(type, data, fn) {   
  458.             return this.each(function() {   
  459.                 jQuery.event.trigger(type, data, thistrue, fn);   
  460.             });   
  461.         },   
  462.         //这个特别的方法将会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作.   
  463.         triggerHandler : function(type, data, fn) {   
  464.             return this[0]   
  465.                     && jQuery.event.trigger(type, data, this[0], false, fn);   
  466.         },   
  467.            
  468.         //每次点击后依次调用函数。   
  469.         toggle : function(fn) {        
  470.             var args = arguments, i = 1;   
  471.                
  472.             while (i < args.length)//每个函数分配GUID   
  473.                 jQuery.event.proxy(fn, args[i++]);   
  474.   
  475.             return this.click(jQuery.event   
  476.                     .proxy(fn, function(event) {//分配GUID                       
  477.                             this.lastToggle = (this.lastToggle || 0) % i;//上一个函数                               
  478.                             event.preventDefault();//阻止缺省动作   
  479.                             //执行参数中的第几个函数,apply可以采用array-like的参数   
  480.                             //With apply, you can use an array literal,    
  481.                             //for example, fun.apply(this, [name, value]),   
  482.                             //or an Array object, for example, fun.apply(this, new Array(name, value)).    
  483.                             return args[this.lastToggle++].apply(this,   
  484.                                     arguments) || false;   
  485.                         }));   
  486.         },   
  487.            
  488.         //一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法。   
  489.         //这是一个自定义的方法,它为频繁使用的任务提供了一种“保持在其中”的状态。   
  490.         //当鼠标移动到一个匹配的元素上面时,会触发指定的第一个函数。当鼠标移出这个元素时,   
  491.         //会触发指定的第二个函数。而且,会伴随着对鼠标是否仍然处在特定元素中的检测(例如,处在div中的图像),   
  492.         //如果是,则会继续保持“悬停”状态,而不触发移出事件(修正了使用mouseout事件的一个常见错误)。   
  493.         hover : function(fnOver, fnOut) {   
  494.             return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);   
  495.         },   
  496.            
  497.         //dom ready时执行 fn   
  498.         ready : function(fn) {             
  499.             bindReady();//注册监听             
  500.             if (jQuery.isReady)//ready就运行                  
  501.                 fn.call(document, jQuery);             
  502.             else  
  503.                 // 增加这个函数到queue中。可见支持无数的ready的调用。   
  504.                 jQuery.readyList.push(function() {   
  505.                     return fn.call(this, jQuery);   
  506.                 });   
  507.   
  508.             return this;   
  509.         }   
  510.     });   
  511.   
  512. jQuery.extend( {   
  513.     isReady : false,   
  514.     readyList : [],   
  515.     // Handle when the DOM is ready   
  516.         ready : function() {               
  517.             if (!jQuery.isReady) {         
  518.                 jQuery.isReady = true;   
  519.                    
  520.                 if (jQuery.readyList) {                    
  521.                     jQuery.each(jQuery.readyList, function() {   
  522.                         this.call(document);   
  523.                     });                
  524.                     jQuery.readyList = null;   
  525.                 }   
  526.                    
  527.                 jQuery(document).triggerHandler("ready");   
  528.             }   
  529.         }   
  530.     });   
  531.   
  532. var readyBound = false;   
  533.   
  534. function bindReady() {   
  535.     if (readyBound)   
  536.         return;   
  537.     readyBound = true;   
  538.   
  539.     // Mozilla, Opera, webkit nightlies 支持DOMContentLoaded事件       
  540.     if (document.addEventListener && !jQuery.browser.opera)   
  541.         //当DOMContentLoaded事件触发时就运行jQuery.ready   
  542.         document.addEventListener("DOMContentLoaded", jQuery.ready, false);   
  543.   
  544.     //IE或不是frame的window   
  545.     if (jQuery.browser.msie && window == top)   
  546.         (function() {   
  547.             if (jQuery.isReady)   
  548.                 return;   
  549.             try {   
  550.                 // 在ondocumentready之前,一直都会抛出异常                 
  551.                 // http://javascript.nwbox.com/IEContentLoaded/   
  552.                 document.documentElement.doScroll("left");   
  553.             } catch (error) {   
  554.                 //一直运行bindReady()(=arguments.callee)   
  555.                 setTimeout(arguments.callee, 0);   
  556.                 return;   
  557.             }              
  558.             jQuery.ready();//documentready就运行jQuery.ready   
  559.         })();   
  560.   
  561.     if (jQuery.browser.opera)   
  562.         document.addEventListener("DOMContentLoaded", function() {   
  563.             if (jQuery.isReady)   
  564.                 return;   
  565.                 //只有styleSheets完全enable时,才是完全的load,其实还有pic   
  566.             for (var i = 0;i < document.styleSheets.length; i++)   
  567.                 if (document.styleSheets[i].disabled) {//通过styleSheets来判断   
  568.                     setTimeout(arguments.callee, 0);   
  569.                     return;   
  570.                 }              
  571.                 jQuery.ready();   
  572.             }, false);   
  573.   
  574.     if (jQuery.browser.safari) {   
  575.         var numStyles;   
  576.         (function() {   
  577.             if (jQuery.isReady)   
  578.                 return;   
  579.                 //首先得得到readyState=loaded或=complete   
  580.             if (document.readyState != "loaded"  
  581.                     && document.readyState != "complete") {   
  582.                 setTimeout(arguments.callee, 0);   
  583.                 return;   
  584.             }   
  585.             //取得style的length,比较它们之间的长度,看看是不是完成loaded   
  586.             if (numStyles === undefined)   
  587.                 numStyles = jQuery("style, link[rel=stylesheet]").length;   
  588.             if (document.styleSheets.length != numStyles) {   
  589.                 setTimeout(arguments.callee, 0);   
  590.                 return;   
  591.             }              
  592.             jQuery.ready();   
  593.         })();   
  594.     }   
  595.   
  596.     //最后只能依赖于window.load.   
  597.     jQuery.event.add(window, "load", jQuery.ready);   
  598. }   
  599.   
  600. //为jquery对象增加常用的事件方法   
  601. jQuery   
  602.         .each(   
  603.                 ("blur,focus,load,resize,scroll,unload,click,dblclick,"  
  604.                         + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + "submit,keydown,keypress,keyup,error")   
  605.                         .split(","), function(i, name) {                       
  606.                 jQuery.fn[name] = function(fn) {   
  607.                     return fn ? this.bind(name, fn) : this.trigger(name);   
  608.                 };   
  609.             });   
  610.   
  611. // Prevent memory leaks in IE   
  612. // And prevent errors on refresh with events like mouseover in other browsers   
  613. // Window isn't included so as not to unbind existing unload events   
  614. jQuery(window).bind('unload', function() {   
  615.     for (var id in jQuery.cache)   
  616.         // Skip the window   
  617.         if (id != 1 && jQuery.cache[id].handle)   
  618.             jQuery.event.remove(jQuery.cache[id].handle.elem);   
  619. });  
原文地址:https://www.cnblogs.com/rooney/p/1346132.html