欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

jQuery 1.9.1源碼分析系列(十)事件系統(tǒng)之綁定事件

 更新時(shí)間:2015年11月19日 09:15:02   作者:chua1989  
這篇文章主要介紹了jQuery 1.9.1源碼分析系列(十) 事件系統(tǒng)——綁定事件的相關(guān)資料,需要的朋友可以參考下

事件綁定的方法有很多種,使用了jquery那么原理那種綁定方式(elem.click = function(){...}))就不太想推薦給大家了。最主要的原因是elem.click=fn這種方式只能綁定一個(gè)事件處理,多次綁定的只會(huì)保留最后一次綁定的結(jié)果。

下面給大家介紹jquery綁定事件的方式有哪些吧。

復(fù)制代碼 代碼如下:

jQuery.fn.eventType([[data,] fn])

比如eventType指的是事件類型,比如click: $("#chua").click(fn);

data這個(gè)參數(shù)一般都不會(huì)使用。這種方式事件綁定在("#chua")上,沒有委托事件,和js原生的事件綁定更接近。我們看一下源碼

jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
  "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
  "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
      //合并15種事件統(tǒng)一增加到j(luò)Query.fn上,內(nèi)部調(diào)用this.on / this.trigger
      jQuery.fn[ name ] = function( data, fn ) {
      return arguments.length > 0 ?
      this.on( name, null, data, fn ) :
      //如果不帶參數(shù)表示立刻觸發(fā)指定事件
      this.trigger( name );
   };
});
jQuery.fn.bind( types[, data], fn )

  比如$("#chua").bind("click",fn)。直接將事件綁定到$("#chua")上,沒有委托事件。源碼

bind: function( types, data, fn ) {
 return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
 return this.off( types, null, fn );
}
 jQuery.fn.delegate(selector, types[, data], fn)

  顧名思義delegate這個(gè)函數(shù)是用來做事件委托的,將選擇器selector對(duì)應(yīng)的響應(yīng)處理委托給當(dāng)前jQuery所匹配的元素。

  比如:$(document).delegate('#big',"click",dohander);分析到這里順便分析一下事件委托的處理流程。

  當(dāng)點(diǎn)擊"#big"元素的時(shí)候,事件click會(huì)冒泡直到document節(jié)點(diǎn);

  document綁定了處理事件,這個(gè)處理事件會(huì)調(diào)用到事件分發(fā)器dispatch;

  dispatch中取出對(duì)應(yīng)事件類型click的所有的委托事件列表handlers;

  根據(jù)事件源event.target過濾出委托事件列表handlers中每一個(gè)元素的selector屬性對(duì)應(yīng)的節(jié)點(diǎn)處于事件原和委托節(jié)點(diǎn)document之間(包括事件源)的委托事件,保存為handlerQueue;

  執(zhí)行handlerQueue里面的事件處理。

  上面是一個(gè)大致的流程,后續(xù)會(huì)詳細(xì)分析。先看delegate源碼

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 );
}
jQuery.fn.one( types[, selector[, data]], fn )

  通過one()函數(shù)綁定的事件處理函數(shù)都是一次性的,只有首次觸發(fā)事件時(shí)會(huì)執(zhí)行該事件處理函數(shù)。觸發(fā)之后,jQuery就會(huì)移除當(dāng)前事件綁定。

  比如$("#chua").one("click",fn);為#chua節(jié)點(diǎn)綁定一次性的click事件

  $(document).one("click","#chua",fn);將#chua的click事件委托給document處理。源碼

one: function( types, selector, data, fn ) {
  return this.on( types, selector, data, fn, 1 );
} 
jQuery.fn.trigger(type[, data])
jQuery.fn.triggerHandler(type[, data])

  trigger觸發(fā)jQuery對(duì)象所匹配的每一個(gè)元素對(duì)應(yīng)type類型的事件。比如$("#chua").trigger("click");

  triggeHandler只觸發(fā)jQuery對(duì)象所匹配的元素中的第一個(gè)元素對(duì)應(yīng)的type類型的事件,且不會(huì)觸發(fā)事件的默認(rèn)行為。

//立刻觸發(fā)jQuery對(duì)象內(nèi)所有元素的指定type的事件
trigger: function( type, data ) {
 return this.each(function() {
  jQuery.event.trigger( type, data, this );
 });
},
//立刻觸發(fā)jQuery對(duì)象內(nèi)第一個(gè)元素的指定type的事件,且不會(huì)觸發(fā)事件(比如表單提交)的默認(rèn)行為
triggerHandler: function( type, data ) {
 var elem = this[0];
 if ( elem ) {
  return jQuery.event.trigger( type, data, elem, true );
 }
}

  上面分析了那么些個(gè)事件綁定,有么有發(fā)現(xiàn)他們都是使用.on方式綁定的?這也是為什么提倡統(tǒng)一使用on來綁定的原因(one方式除外)。

jQuery.fn.on( types[, selector[, data]], fn )

  .on的事件綁定一半的代碼都實(shí)在處理傳遞不同參數(shù)的處理,這也是jQuery的口號(hào)Write less, do more的代價(jià)吧。最終使用jQuery.event.add來綁定事件。

  jQuery.event.add綁定事件有幾個(gè)比較關(guān)鍵的地方:

  第一個(gè),使用內(nèi)部緩存來保存節(jié)點(diǎn)elem的事件信息

//獲取緩存數(shù)據(jù) 
       elemData = jQuery._data( elem );
       ...
       
       //設(shè)置緩存數(shù)據(jù)
   if ( !(events = elemData.events) ) {
    events = elemData.events = {};
   }
   if ( !(eventHandle = elemData.handle) ) {
    eventHandle = elemData.handle = function( e ) {
     ...
    };
    //將elem作為handle函數(shù)的一個(gè)特征防止ie非本地事件引起的內(nèi)存泄露
    eventHandle.elem = elem;
   }

  第二個(gè),設(shè)置綁定事件信息,特別是指定的選擇器selector、響應(yīng)處理handler、響應(yīng)事件類型type、命名空間namespace

 // handleObj:設(shè)置綁定事件信息。貫穿整個(gè)事件處理
  handleObj = jQuery.extend({
   type: type,
   origType: origType,
   data: data,
   handler: handler,
   guid: handler.guid,
   selector: selector,
   // For use in libraries implementing .is(). We use this for POS matching in `select`
   //"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
   //whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
   //用來判斷親密關(guān)系
   needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
   namespace: namespaces.join(".")
  }, handleObjIn );

  第三個(gè),節(jié)點(diǎn)的事件列表中,真正的委托事件列表放置在前面,和delegateCount屬性同步,即events.click.length假設(shè)為3,events.click.delegateCount假設(shè)為2。那么events.click[0]和events.click[1]所指定事件是委托事件。第三個(gè)events.click[2]對(duì)應(yīng)的事件不是委托事件,而是節(jié)點(diǎn)自身的事件。

 //將事件對(duì)象handleObj添加到元素的處理列表,委托事件放在前面,委托代理計(jì)數(shù)遞增
  if ( selector ) {
   handlers.splice( handlers.delegateCount++, 0, handleObj );
  } else {
   handlers.push( handleObj );
  }

  源碼和添加事件后的結(jié)構(gòu)上一章已經(jīng)分析,詳情請(qǐng)點(diǎn)擊查看

  綁定有一個(gè)公用函數(shù)jQuery.fn.on。解綁同樣有一個(gè)公用函數(shù)jQuery.fn.off

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

  這里的傳參有個(gè)比較特殊的情況:當(dāng)types是瀏覽器事件對(duì)象event的時(shí)候,表示要去掉(解綁)委托節(jié)點(diǎn)上event.selector指定的委托事件

//傳入的參數(shù)是事件且綁定了處理函數(shù)
if ( types && types.preventDefault && types.handleObj ) {
  // ( event ) dispatched jQuery.Event
  handleObj = types.handleObj;
  //types.delegateTarget是事件托管對(duì)象
  jQuery( types.delegateTarget ).off(
   //組合jQuery識(shí)別的type
   handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
   handleObj.selector,
   handleObj.handler
   );
  return this;
}

  無論如何最終都是調(diào)用jQuery.event.remove函數(shù)來解綁事件。

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

off: function( types, selector, fn ) {
  var handleObj, type;
  //傳入的參數(shù)是事件且綁定了處理函數(shù)
  if ( types && types.preventDefault && types.handleObj ) {
  // ( event ) dispatched jQuery.Event
  handleObj = types.handleObj;
  //types.delegateTarget是事件托管對(duì)象
  jQuery( types.delegateTarget ).off(
   //組合jQuery識(shí)別的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 );
  });
}

  接下來分析一下事件解綁的低級(jí)api jQuery.event.remove。

jQuery.event.remove

  jQuery使用.off()函數(shù)傷處綁定的事件時(shí)內(nèi)部調(diào)用的基礎(chǔ)函數(shù)是jQuery.event.remove。該函數(shù)的處理流程如下

  1. 分解傳入的要?jiǎng)h除的事件類型types,遍歷類型,如果要?jiǎng)h除的事件沒有事件名,只有命名空間則表示刪除該命名空間下所有綁定事件

//分解types為type.namespace為單位元素的數(shù)組
types = ( types || "" ).match( core_rnotwhite ) || [""];
t = types.length;
while ( t-- ) {
   tmp = rtypenamespace.exec( types[t] ) || [];
   type = origType = tmp[1];
   namespaces = ( tmp[2] || "" ).split( "." ).sort();

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

  2. 遍歷類型過程中,刪除匹配的事件,代理計(jì)數(shù)修正

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. 如果節(jié)點(diǎn)上指定類型的事件處理器已經(jīng)為空,則將events上的該類型的事件處理對(duì)象移除

// 移除事件處理對(duì)象
// (移除特殊事件處理過程中避免潛在的無限遞歸,下一章會(huì)專門詳解這種情況)
if ( origCount && !handlers.length ) {
//例如 var js_obj = document.createElement("div"); js_obj.onclick = function(){ …}
//上面的js_obj是一個(gè)DOM元素的引用,DOM元素它長(zhǎng)期在網(wǎng)頁當(dāng)中,不會(huì)消失,而這個(gè)DOM元素的一屬性onclick,又是內(nèi)部的函數(shù)引用(閉包),而這個(gè)匿名函數(shù)又和js_obj之間有隱藏的關(guān)聯(lián)(作用域鏈)所以形成了一個(gè),循環(huán)引用.
if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
  jQuery.removeEvent( elem, type, elemData.handle );
}

delete events[ type ];
}

  4. 如果節(jié)點(diǎn)上沒有任何綁定的事件,則清空事件處理入口handle

if ( jQuery.isEmptyObject( events ) ) {
  delete elemData.handle;
  //removeData還檢事件對(duì)象是否為空,所以使用它替代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中的內(nèi)存泄露
    // detachEvent需要傳遞第一個(gè)參數(shù),不能是undefined的
    if ( typeof elem[ name ] === core_strundefined ) {
     elem[ name ] = null;
    }
    elem.detachEvent( name, handle );
   }
};

以上內(nèi)容是小編給大家介紹的jQuery 1.9.1源碼分析系列(十)事件系統(tǒng)之綁定事件,希望大家喜歡。

相關(guān)文章

  • 基于jQuery實(shí)現(xiàn)的旋轉(zhuǎn)彩圈實(shí)例

    基于jQuery實(shí)現(xiàn)的旋轉(zhuǎn)彩圈實(shí)例

    這篇文章主要介紹了基于jQuery實(shí)現(xiàn)的旋轉(zhuǎn)彩圈,涉及jQuery定時(shí)操作頁面元素的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • jQuery用FormData實(shí)現(xiàn)文件上傳的方法

    jQuery用FormData實(shí)現(xiàn)文件上傳的方法

    眾所周知文件上傳是Web開發(fā)中的重要話題,最直接和簡(jiǎn)單的方式是通過表單直接提交文件。 下面這篇文章小編就來和大家分享jQuery利用FormData實(shí)現(xiàn)文件上傳的方法,文中介紹的方法簡(jiǎn)單易懂,相信對(duì)大家的理解和學(xué)習(xí)很有幫助,有需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2016-11-11
  • 深入理解jquery自定義動(dòng)畫animate()

    深入理解jquery自定義動(dòng)畫animate()

    下面小編就為大家?guī)硪黄钊肜斫鈐query自定義動(dòng)畫animate()。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-05-05
  • 分享14個(gè)很酷的jQuery導(dǎo)航菜單插件

    分享14個(gè)很酷的jQuery導(dǎo)航菜單插件

    本文介紹了14個(gè)很酷的jQuery導(dǎo)航菜單插件,它們夠漂亮、簡(jiǎn)單,并且完全兼容各種類型的web瀏覽器。
    2011-04-04
  • jQuery操作屬性和樣式詳解

    jQuery操作屬性和樣式詳解

    下面小編就為大家?guī)硪黄猨Query操作屬性和樣式詳解。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-04-04
  • 關(guān)于Jquery操作Cookie取值錯(cuò)誤的解決方法

    關(guān)于Jquery操作Cookie取值錯(cuò)誤的解決方法

    使用JQuery操作cookie時(shí) 發(fā)生取的值不正確,結(jié)果發(fā)現(xiàn)cookie有四個(gè)不同的屬性,下面與大家分享下錯(cuò)誤的原因及解決方法
    2013-08-08
  • 利用瀏覽器全屏api實(shí)現(xiàn)js全屏

    利用瀏覽器全屏api實(shí)現(xiàn)js全屏

    這篇文章主要介紹了利用瀏覽器全屏api實(shí)現(xiàn)js全屏的代碼示例,示例中使用了jquery,把這個(gè)庫的地址改成自己的,大家參考使用吧
    2014-01-01
  • Tab頁界面,用jQuery及Ajax技術(shù)實(shí)現(xiàn)

    Tab頁界面,用jQuery及Ajax技術(shù)實(shí)現(xiàn)

    從桌面開發(fā)的時(shí)代開始,Tab頁就是一個(gè)優(yōu)異的界面布局形式,兼有菜單的樣式和充分復(fù)用有限的界面的優(yōu)點(diǎn)。
    2009-09-09
  • jQuery mobile 移動(dòng)web(4)

    jQuery mobile 移動(dòng)web(4)

    這篇文章主要介紹了jQuery mobile 移動(dòng)web(4)的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • jQuery表單域?qū)傩赃^濾器用法分析

    jQuery表單域?qū)傩赃^濾器用法分析

    這篇文章主要介紹了jQuery表單域?qū)傩赃^濾器用法,實(shí)例分析了:checked、:enabled、:disabled:、selected等常用表單域?qū)傩赃^濾器使用技巧,需要的朋友可以參考下
    2015-02-02

最新評(píng)論