jQuery 源码系列(十一)event 整体概述

欢迎来我的专栏检察系列文章。

此次的内容是来引见关于 jQuery 的事宜托付。不过在之前呢有必要先来相识一下 JS 中的事宜托付与冒泡,我之前也写过相似的博客,事宜冒泡与捕捉

《jQuery 源码系列(十一)event 整体概述》

由 JS 事宜引入

事宜是 JS DOM 中极具生机的内容,你能够随时监听 DOM 的变化,并对它们实时的做出回响反映,假如你不是太懂 JS 中的事宜,发起你先去看一些相干引见的文章,直接看 jQuery 中的事宜托付头会头大的。

事宜的处置惩罚递次由两个环节,一个是捕捉环节,一个是冒泡环节,借用他人的一张图:

《jQuery 源码系列(十一)event 整体概述》

假如把处置惩罚也算进的话,全部事宜分为三个阶段,离别是捕捉阶段,目的处置惩罚阶段和冒泡阶段。捕捉阶段由外向内寻觅 target,冒泡阶段由内向外直到根结点。这只是一个事宜,当这三个阶段中又穿插着更多的事宜时,还需要将事宜的实行递次斟酌进去。

而 jQuery 事宜托付的观点:事宜目的本身不处置惩罚事宜,而是将其托付给父元素或先人元素或根元素,而借助事宜的冒泡性子(由内向外)来到达终究处置惩罚事宜。

jQuery 中的事宜优化

起首必需要知道,绑定事宜越多,浏览器内存占用越大,就会间接的影响机能。而且一旦涌现 ajax,部分革新致使从新绑定事宜。

运用事宜托付能够处理以上带来的题目,借助事宜的冒泡,特别当一个父元素的子元素过量,而且子元素绑定的事宜异常多时,托付事宜的作用就体现出来了。

我本人不善于比较 JS 中的机能题目,感兴趣的能够去看看这篇文章关于事宜托付机能的设想和比较。深切明白-事宜托付

在初期的 jQuery 版本,运用的是 .delegate().bind().live()等要领来完成事宜监听,固然也包含.click()要领,跟着 jQuery 的生长,像 live 要领已明白从 jQuery 中删除,而其他的要领,比方 bind 要领也将在 3.0 以后的版本连续删除,取而代之的是 .on()要领。而且剩下的别的要领都是经由过程 on 要领来间接完成的,假如引见,只需要看 on 的源码即可。

on 函数在 jQuery 中的用法也很简单,.on( events [, selector ] [, data ], handler(eventObject) )events 示意绑定的事宜,比方 “click” 或 “click mouseleave”,selector 和 data 是可选的,离别示意要绑定事宜的元素和要实行的数据,handler 示意事宜实行函数。

off 函数的用法 .off( events [, selector ] [, handler ] ),events 代表要移除的事宜,selector 示意挑选的 dom,handler 示意事宜处置惩罚函数。另有更残酷的比方 .off()不接受任何参数,示意着移除一切 on 绑定的函数。

on off 函数源码

虽然我剖析的源码时 jQuery 3.1.1,但这个时刻 bind 和 delegate 函数并没有从源码中移除呢,先来看看它们怎样挪用 on:

jQuery.fn.extend( {
  bind: function( types, data, fn ) {
    return this.on( types, null, data, fn );
  },
  unbind: function( types, fn ) {
    return this.off( types, null, fn );
  },
  delegate: function( selector, types, data, fn ) {
    return this.on( types, selector, data, fn );
  },
  undelegate: function( selector, types, fn ) {
    // ( namespace ) or ( selector, types [, fn] )
    return arguments.length === 1 ?
      this.off( selector, "**" ) :
      this.off( types, selector || "**", fn );
  }
} );

能够看得出来,全都被 on 和 off 这两个函数来处置惩罚了。

jQuery.fn.extend( {
  on: function (types, selector, data, fn) {
    // on 又依托于全局的 on 函数
    return on(this, types, selector, data, fn);
  }
} );
function on( elem, types, selector, data, fn, one ) {
  var origFn, type;

  // 支撑 object 的状况
  if ( typeof types === "object" ) {

    // ( types-Object, selector, data )
    if ( typeof selector !== "string" ) {

      // ( types-Object, data )
      data = data || selector;
      selector = undefined;
    }
    // 一次实行 object 的每个
    for ( type in types ) {
      on( elem, type, selector, data, types[ type ], one );
    }
    return elem;
  }
  // 参数为两个的状况
  if ( data == null && fn == null ) {

    // ( types, fn )
    fn = selector;
    data = selector = undefined;
  } else if ( fn == null ) {
    if ( typeof selector === "string" ) {

      // ( types, selector, fn )
      fn = data;
      data = undefined;
    } else {

      // ( types, data, fn )
      fn = data;
      data = selector;
      selector = undefined;
    }
  }
  if ( fn === false ) {
    // returnFalse 是一个返回 false 的函数
    fn = returnFalse;
  } else if ( !fn ) {
    return elem;
  }

  if ( one === 1 ) {
    origFn = fn;
    fn = function( event ) {

      // Can use an empty set, since event contains the info
      jQuery().off( event );
      return origFn.apply( this, arguments );
    };

    // Use same guid so caller can remove using origFn
    fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
  }
  return elem.each( function() {
    // 症结
    jQuery.event.add( this, types, fn, data, selector );
  } );
}

是的,你没有看错,这个全局的 on 函数,实在只是起到了校订参数的作用,而真正的大头是:

jQuery.event = {
  global = {},
  add: function(){...},
  remove: function(){...},
  dispatch: function(){...},
  handlers: function(){...},
  addProp: function(){...},
  fix: function(){...},
  special: function(){...}
}

off 函数:

jQuery.fn.off = function (types, selector, fn) {
  var handleObj, type;
  if (types && types.preventDefault && types.handleObj) {
    // ( event )  dispatched jQuery.Event
    handleObj = types.handleObj;
    jQuery(types.delegateTarget).off(
      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);
  });
}

总结

可见 jQuery 关于参数的纵容致使其处置惩罚起来异常庞杂,不过关于运用者来讲,却异常大方便。

托付事宜也带来了一些不足,比方一些事宜没法冒泡,load、submit 等,会加大治理等庞杂,不好模仿用户触发事宜等。

参考

jQuery 2.0.3 源码剖析 事宜绑定 – bind/live/delegate/on
深切明白-事宜托付
.on()

本文在 github 上的源码地点,欢迎来 star。

欢迎来我的博客交换。

    原文作者:songjz
    原文地址: https://segmentfault.com/a/1190000008494144
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞