jQuery 1.9.1源码分析系列(十)事件系统之绑定事件


事件绑定的方法有很多种,使用了jquery那么原理那种绑定方式(elem.click = function(){...}))就不太想推荐给大家了。最主要的原因是elem.click=fn这种方式只能绑定一个事件处理,多次绑定的只会保留最后一次绑定的结果。

下面给大家介绍jquery绑定事件的方式有哪些吧。

详情请点击查看

  绑定有一个公用函数jQuery.fn.on。解绑同样有一个公用函数jQuery.fn.off

jQuery.fn.off([ types[, selector][, fn]] )

  这里的传参有个比较特殊的情况:当types是浏览器事件对象event的时候,表示要去掉(解绑)委托节点上event.selector指定的委托事件

//传入的参数是事件且绑定了处理函数
if ( types && types.preventDefault && types.handleObj ) {
  // ( event ) dispatched jQuery.Event
  handleObj = types.handleObj;
  //types.delegateTarget是事件托管对象
  jQuery( types.delegateTarget ).off(
   //组合jQuery识别的type
   handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
   handleObj.selector,
   handleObj.handler
   );
  return this;
}

  无论如何最终都是调用jQuery.event.remove函数来解绑事件。

  jQuery.fn.off完整的源码如下

off: function( types, selector, fn ) {
  var handleObj, type;
  //传入的参数是事件且绑定了处理函数
  if ( types && types.preventDefault && types.handleObj ) {
  // ( event ) dispatched jQuery.Event
  handleObj = types.handleObj;
  //types.delegateTarget是事件托管对象
  jQuery( types.delegateTarget ).off(
   //组合jQuery识别的type
   handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
   handleObj.selector,
   handleObj.handler
   );
  return this;
  }
  if ( typeof types === "object" ) {
  // ( types-object [, selector] )
  for ( type in types ) {
   this.off( type, selector, types[ type ] );
  }
  return this;
  }
  if ( selector === false || typeof selector === "function" ) {
  // ( types [, fn] )
  fn = selector;
  selector = undefined;
  }
  if ( fn === false ) {
  fn = returnFalse;
  }
  return this.each(function() {
  jQuery.event.remove( this, types, fn, selector );
  });
}

  接下来分析一下事件解绑的低级api jQuery.event.remove。

jQuery.event.remove

  jQuery使用.off()函数伤处绑定的事件时内部调用的基础函数是jQuery.event.remove。该函数的处理流程如下

  1. 分解传入的要删除的事件类型types,遍历类型,如果要删除的事件没有事件名,只有命名空间则表示删除该命名空间下所有绑定事件

//分解types为type.namespace为单位元素的数组
types = ( types || "" ).match( core_rnotwhite ) || [""];
t = types.length;
while ( t-- ) {
   tmp = rtypenamespace.exec( types[t] ) || [];
   type = origType = tmp[1];
   namespaces = ( tmp[2] || "" ).split( "." ).sort();

   //解绑当前元素的当前命名空间(types[ t ])上所有的事件
   if ( !type ) {
    for ( type in events ) {
     jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
    }
    continue;
   }
   ...

  2. 遍历类型过程中,删除匹配的事件,代理计数修正

type = ( selector ? special.delegateType : special.bindType ) || type;
handlers = events[ type ] || [];
tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
//删除匹配事件
origCount = j = handlers.length;
while ( j-- ) {
   handleObj = handlers[ j ];

   //各种满足移除事件的条件才能移除
   if ( ( mappedTypes || origType === handleObj.origType ) &&
    ( !handler || handler.guid === handleObj.guid ) &&
    ( !tmp || tmp.test( handleObj.namespace ) ) &&
    ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
    handlers.splice( j, 1 ); 
        if ( handleObj.selector ) {
          handlers.delegateCount--;
        }
        if ( special.remove ) {
          special.remove.call( elem, handleObj );
        }
   }
}

  3. 如果节点上指定类型的事件处理器已经为空,则将events上的该类型的事件处理对象移除

// 移除事件处理对象
// (移除特殊事件处理过程中避免潜在的无限递归,下一章会专门详解这种情况)
if ( origCount && !handlers.length ) {
//例如 var js_obj = document.createElement("div"); js_obj.onclick = function(){ …}
//上面的js_obj是一个DOM元素的引用,DOM元素它长期在网页当中,不会消失,而这个DOM元素的一属性onclick,又是内部的函数引用(闭包),而这个匿名函数又和js_obj之间有隐藏的关联(作用域链)所以形成了一个,循环引用.
if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
  jQuery.removeEvent( elem, type, elemData.handle );
}

delete events[ type ];
}

  4. 如果节点上没有任何绑定的事件,则清空事件处理入口handle

if ( jQuery.isEmptyObject( events ) ) {
  delete elemData.handle;
  //removeData还检事件对象是否为空,所以使用它替代delete
  jQuery._removeData( elem, "events" );
}

拓展: 浏览器事件删除jQuery.removeEvent

jQuery.removeEvent = document.removeEventListener ?
function( elem, type, handle ) {
   if ( elem.removeEventListener ) {
    elem.removeEventListener( type, handle, false );
   }
} :
function( elem, type, handle ) {
   var name = "on" + type;
   if ( elem.detachEvent ) {
    // #8545, #7054,避免自定义事件在IE6-8中的内存泄露
    // detachEvent需要传递第一个参数,不能是undefined的
    if ( typeof elem[ name ] === core_strundefined ) {
     elem[ name ] = null;
    }
    elem.detachEvent( name, handle );
   }
};

以上内容是小编给大家介绍的jQuery 1.9.1源码分析系列(十)事件系统之绑定事件,希望大家喜欢。


« 
» 

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3