jquery的on

南風一濺發表於2018-12-10

以下見解基於jquery v1.12.4

jquery的on() 方法在被選元素及子元素上新增一個或多個事件處理程式

$(selector).on(event,childSelector,data,function)

一直比較好奇jquery是怎麼處理多個引數可以只傳幾個,且順序不強制的,遂琢磨了下jquery的on方法

1、 dom結構

<div id="div1">
  <p id="p1" class="p-text">文字1</p>
  <p id="p2" class="p-text">文字2</p>
</div>
複製程式碼

2、 基本用法

2.1、 最簡單的用法

// 點選#div1列印 *點選了*
$('#div1').on('click', function (e) {
  console.log('點選了')
})
複製程式碼

2.2、 事件委託

// 點選任意p標籤列印 *點選了*
$('#div1').on('click', 'p', function (e) {
  console.log('點選了')
})
複製程式碼

2.3、 引數齊全的事件繫結

// 列印出*123*
$('#div1').on('click', 123, function (e) {
  console.log(e.data)
})
// 點選不會發生任何事情
$('#div1').on('click', '123', function (e) {
  console.log(e.data)
})
複製程式碼

問題來了,在事件委託那裡,我傳入的第2個元素是字串'p',在這裡傳入字串'123'點選毫無反應,傳入數字123則可以觸發。對比on方法的引數順序,可以發現以上三種例子的順序都不對應 這就引出了我一開始的問題:jquery是怎麼處理多個引數可以只傳幾個,且順序不強制的

通過研究一波jquery原始碼發現,其實原理很簡單,就是對傳入的引數進行(型別、null、undefined)判斷 在jquery內部,會按on方法提供的(約定的)順序對傳入的引數進行判斷並轉換成其需要的順序

擷取部分程式碼:

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;
   	}
   }
複製程式碼

原始碼位置:function on( elem, types, selector, data, fn, one )

3、 批量繫結事件

3.1、 批量繫結相同處理

// 點選、滑鼠移入列印*123*
$('#div1').on('click mouseenter', 123, function (e) {
    console.log(e.data)
  })
複製程式碼

3.2、 批量繫結不同處理

// 點選、滑鼠移入、移出列印對應訊息
$('#div1').on(
    {
      click: function (e) {console.log('點選:' + e.data)},
      mouseenter: function (e) {console.log('滑鼠進入:' + e.data)},
      mouseleave: function (e) {console.log('滑鼠移出!')}
    }, 
    123
  )
複製程式碼

批量繫結不同處理,傳入物件形式的引數,內部對引數進行了for...in解構,處理位置:

...
for ( type in types ) {
  on( elem, type, selector, data, types[ type ], one );
}
...
複製程式碼

兩種批量繫結事件最終都從on進入**add: function( elem, types, handler, data, selector ) **,在add方法進行最終的事件新增。 兩者最終都會經過add方法的如下程式碼處理:

...
// Handle multiple events separated by a space
types = ( types || "" ).match( rnotwhite ) || [ "" ]; // types被轉為陣列,進入while迴圈遍歷
t = types.length;
while ( t-- ) {
...
複製程式碼

4、 總結

雖然jquery內建了很多方便的處理,但還是有很多種情況考慮不到,比如下面這種情況就無法成功

$('#div1').on(['click', 'mouseenter'], function (e) {
   console.log('點選了')
 })
複製程式碼

所以,呼叫方法的時候還是按照約定好的資料結構來

相關文章