zoukankan      html  css  js  c++  java
  • jquery event addEvent 分析

    1. Jquery提供了一些来进行regist,remove,fire事件的方法。   
    2. 6.2.1 Register   
    3. 对于注册事件,jquery提供了bind、one、toggle、hover四种注册事件的方法, bind是最基本的方法。One是注册只运行一次的方法,toggle注册交替运行的方法。Hover是注册鼠标浮过的方法。   
    4. bind : function(type, data, fn) {   
    5.     return type == "unload" ? this.one(type, data, fn) : this  
    6.         .each(function() {// fn || data, fn && data实现了data参数可有可无   
    7.                     jQuery.event.add(this, type, fn || data, fn && data);   
    8.                 }); },   
    9. Bind中对于unload的事件,只能运行一次,其它的就采用默认的注册方式。   
    10. // 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数。   
    11. // 在每个对象上,这个事件处理函数只会被执行一次。其他规则与bind()函数相同。   
    12. // 这个事件处理函数会接收到一个事件对象,可以通过它来阻止(浏览器)默认的行为。   
    13. // 如果既想取消默认的行为,又想阻止事件起泡,这个事件处理函数必须返回false。   
    14.     one : function(type, data, fn) {   
    15.       var one = jQuery.event.proxy(fn || data, function(event) {   
    16.             jQuery(this).unbind(event, one);   
    17.             return (fn || data).apply(this, arguments);/this->当前的元素   
    18.                 });   
    19.             return this.each(function() {   
    20.                 jQuery.event.add(this, type, one, fn && data);   
    21.             });   
    22.         },   
    23. One与bind基本上差不多,不同的在调用jQuery.event.add时,把注册的事件处理的函数做了一个小小的调整。One调用了jQuery.event.proxy进行了代理传入的事件处理函数。在事件触发调用这个代理的函数时,先把事件从cache中删除,再执行注册的事件函数。这里就是闭包的应用,通过闭包得到fn注册的事件函数的引用。   
    24. //一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法。   
    25. //这是一个自定义的方法,它为频繁使用的任务提供了一种“保持在其中”的状态。   
    26.  //当鼠标移动到一个匹配的元素上面时,会触发指定的第一个函数。当鼠标移出这个元素时,   
    27. /会触发指定的第二个函数。而且,会伴随着对鼠标是否仍然处在特定元素中的检测(例如,处在div中的图像),   
    28.   //如果是,则会继续保持“悬停”状态,而不触发移出事件(修正了使用mouseout事件的一个常见错误)。   
    29.         hover : function(fnOver, fnOut) {   
    30.             return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);   
    31.         },   
    32. Hover则是建立在bind的基础之上。   
    33. //每次点击后依次调用函数。   
    34. toggle : function(fn) {        
    35. var args = arguments, i = 1;   
    36. while (i < args.length)//每个函数分配GUID   
    37.         jQuery.event.proxy(fn, args[i++]);//修改后的还在args中   
    38. return this.click(jQuery.event.proxy(fn, function(event) {//分配GUID          this.lastToggle = (this.lastToggle || 0) % i;//上一个函数                event.preventDefault();//阻止缺省动作   
    39.         //执行参数中的第几个函数,apply可以采用array-like的参数   
    40.         return args[this.lastToggle++].apply(this,arguments)||false;   
    41.     }));   
    42.     },   
    43. Toggle中参数可以是多个fn。先把它们代码生成UUID。之后调用click的方法来注册再次进行代理的callback。这个函数在事件触发时运行,它先计算上一次是执行了参数中的那个函数。之后阻止缺省动作。之后找到下一个函数运行。   
    44. //为jquery对象增加常用的事件方法   
    45. jQuery.each(   
    46.     ("blur,focus,load,resize,scroll,unload,click,dblclick,"  
    47.     + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"    
    48. "submit,keydown,keypress,keyup,error").split(","),    
    49. function(i, name) {jQuery.fn[name] = function(fn) {   
    50.                     return fn ? this.bind(name, fn) : this.trigger(name);   
    51.                 };});   
    52. Jquery增加了一个常用的事件处理方法,包含上面调用的click。这里可以看出这里还是调用bind进行注册。当然这里还可以通过程序实现去触发事件。   
    53.   
    54. 上面的众多方法都是注册事件,其最终都落在jQuery.event.add();来完成注册的功能。如果我们采用Dom0或DOM1的事件方法,我们会采用elem.onclick=function(){}来为元素的某一种事件来注册处理函数。这个最大的缺点就是每个一个事件只是一个处理函数。在dom1的方式中有改进,我们可以采用elem.addEventListener(type, handle, false)为元素的事件注册多个处理函数。   
    55. 这样的处理方式还不是很完美,如果我们只这个事件运行一次就有点麻烦了。我们要在事件的处理函数中最后进行elem.removeEventListener来取消事件的监听。这样做可能会有事务上的问题。如果第一个事件处理函数在没有取消事件监听之前,就再次触发了怎么办?   
    56. 还有采用浏览器的方式,它不支持自定义事件的注册和处理,还不能为多个事件注册同一个处理函数。   
    57. jQuery.event = {// add 事件到一个元素上。   
    58. add : function(elem, types, handler, data) {   
    59. if (elem.nodeType == 3 || elem.nodeType == 8return;// 空白节点或注释   
    60.     // IE不能传入window,先复制一下。   
    61. if (jQuery.browser.msie && elem.setInterval) elem = window;   
    62. // 为handler分配一个全局唯一的Id   
    63. if (!handler.guid)  handler.guid = this.guid++;   
    64. // 把data附到handler.data中   
    65. if (data != undefined) {                                             ①   
    66. var fn = handler;   
    67. handler =this.proxy(fn,function(){return fn.apply(this,arguments);});   
    68. handler.data = data;   
    69.     }   
    70. // 初始化元素的events。如果没有取到events中值,就初始化data: {}       ②   
    71. var events =jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),   
    72. // 如果没有取到handle中值,就初始化data: function() {....}         ③   
    73. handle = jQuery.data(elem, "handle")|| jQuery.data(elem, "handle",   
    74. function() {//处理一个触发器的第二个事件和当page已经unload之后调用一个事件。   
    75.         if (typeof jQuery != "undefined"&& !jQuery.event.triggered)   
    76.             return jQuery.event.handle.apply(//callee.elem=handle.elem   
    77.                    arguments.callee.elem, arguments);   
    78.             });   
    79. // 增加elem做为handle属性,防止IE由于没有本地Event而内存泄露。   
    80. handle.elem = elem;   
    81. // 处理采用空格分隔多个事件名,如jQuery(...).bind("mouseover mouseout", fn);   
    82. jQuery.each(types.split(/\s+/), function(index, type) {       ④   
    83.     // 命名空间的事件,一般不会用到。   
    84. var parts = type.split(".");type = parts[0];handler.type = parts[1];   
    85.     // 捆绑到本元素type事件的所有处理函数   
    86. var handlers = events[type];                                         ⑤   
    87. if (!handlers) {// 没有找到处理函数列表就初始化事件队列   
    88.         handlers = events[type] = {};   
    89.     // 如果type不是ready,或ready的setup执行返回false                 ⑥   
    90. if (!jQuery.event.special[type]|| jQuery.event.special[type].setup   
    91.         .call(elem, data) === false) {// 调用系统的事件函数来注册事件   
    92. if(elem.addEventListener)elem.addEventListener(type,handle,false);   
    93. else if (elem.attachEvent)elem.attachEvent("on" + type, handle);   
    94.            }   
    95. }   
    96. // 把处理器的id和handler形式属性对的形式保存在handlers列表中,   
    97. // 也存在events[type][handler.guid]中。   
    98. handlers[handler.guid] = handler;                                   ⑦   
    99. // 全局缓存这个事件的使用标识   
    100. jQuery.event.global[type] = true;   
    101. });   
    102.   
    103.     elem = null// 防止IE内存泄露。   
    104.     },   
    105.     guid : 1,   
    106.     global : {},   
    107. jQuery.event.add通过jQuery.data把事件相关的事件名和处理函数有机有序地组合起存放在jQuery.cache中与该元素对应的空间里。我们就一个例子分析一下add的过程中:假如我们招待下面jQuery(e1).bind("mouseover mouseout", fn0);jQuery(e1).bind("mouseover mouseout", fn1)的语句。   
    108. 在jQuery(e1).bind("mouseover mouseout", fn0);时,②③都不可能从cache取到数,先初始化。此时的cache:{e1_uuid:{events:{},handle:fn}}。接着在⑤会为mouseover mouseout名初始化。此时的cache: {e1_uuid:{events:{ mouseover:{}, mouseout:{}},handle:fn}}。在⑥处向浏览器的事件中注册处理函数。接着⑦会把处理函数到事件名中。此时的cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}},handle:fn}}。这里可以看出为采用proxy为函数生成uuid的作用了。   
    109. 在jQuery(e1).bind("mouseover mouseout", fn1)时,②③都从cache取到数据{e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}},接着在⑤取到mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}的引用。接着⑦会把处理函数注册到事件名中。此时的cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0, fn1_uuid:fn1,},mouseout:{ fn0_uuid:fn0, fn1_uuid:fn1}},handle:fn}}。   
    110. jQuery.event.add很重要的任务就是把注册的事件函数有序地存放起来。以便remove和fire事件的函数能找到。   
    111. //{elem_uuid_1:{events:{mouseover:{fn_uuid:fn1,fn_uuid1:fn2},   
    112.                 //mouseout:{fn_uuid:fn1,fn_uuid1:fn2}},handle:fn}}  
  • 相关阅读:
    LeetCode 769. Max Chunks To Make Sorted
    LeetCode 845. Longest Mountain in Array
    LeetCode 1059. All Paths from Source Lead to Destination
    1129. Shortest Path with Alternating Colors
    LeetCode 785. Is Graph Bipartite?
    LeetCode 802. Find Eventual Safe States
    LeetCode 1043. Partition Array for Maximum Sum
    LeetCode 841. Keys and Rooms
    LeetCode 1061. Lexicographically Smallest Equivalent String
    LeetCode 1102. Path With Maximum Minimum Value
  • 原文地址:https://www.cnblogs.com/rooney/p/1346469.html
Copyright © 2011-2022 走看看