zepto 事件分析2($.on)

這裏主要分析zepto事件中的$.on函數,先看一下該函數的代碼javascript

$.fn.on = function(event, selector, data, callback, one){
    var autoRemove, delegator, $this = this
    if (event && !isString(event)) {
      //多個事件下的處理
      $.each(event, function(type, fn){
        $this.on(type, selector, data, fn, one)
      })
      return $this
    }
    //根據傳入的參數初始化各個參數
    //(event,data,callback)
    if (!isString(selector) && !isFunction(callback) && callback !== false)
      callback = data, data = selector, selector = undefined
    //(event,selector,callback)
    if (callback === undefined || data === false)
      callback = data, data = undefined
    //callback = function(){return false}
    if (callback === false) callback = returnFalse
    //迭代zepto對象中的元素
    return $this.each(function(_, element){
      if (one) autoRemove = function(e){
        remove(element, e.type, callback)
        return callback.apply(this, arguments)
      }
      //若是有傳入選擇器 定義一個delegator函數
      if (selector) delegator = function(e){
        //從觸發事件目標出發找尋符合selector選擇器的元素
        var evt, match = $(e.target).closest(selector, element).get(0)
        //若是存在而且不是element 
        if (match && match !== element) {
          //對event對象進行轉化操做
          evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})
          return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1)))
        }
      }
      add(element, event, callback, data, selector, delegator || autoRemove)
    })
  }

該函數主要分析的是return 後面的語句,在前面的分析中,分析了each函數和$對象,也就是對$對象中的每個dom進行綁定事件,這裏先跳過autoRemove函數,留在後面分析,若是有傳入選擇器,zepto先定義一個delegator函數,delegator函數中有一個match變量,該變量即爲咱們要綁定事件的目標元素,zepto採用的是事件委託,官方文檔對於closest的定義以下:html

而e.target便是事件觸發的元素,注意:currentTarget和e.target是不一樣的。target在事件流的目標階段;currentTarget在事件流的捕獲,目標及冒泡階段。java

<body>
<div class="out">
    <div class="in"><h2>1`</h2></div>
</div>
</html>
<script type="text/javascript">

function test2(e){
    console.log(e.target);
    console.log(e.currentTarget)
};
var box2 = document.getElementsByClassName('in')[0];
box2.addEventListener("click",test2);

當咱們點擊h2時,target指向<h2>,currentTarget指向<div class='in'>;app

在得到match以後,判斷其是否存在或是否爲元素自己,若是是,則什麼都不作,若是不是,則建立一個新的事件evt,並將原來的事件屬性賦值給evt,並改變currentTarget和 liveFired的屬性值。dom

其中有一個createProxy函數,該函數的功能即爲複製屬性。函數

function createProxy(event) {
    var key, proxy = { originalEvent: event }
    for (key in event)
      if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]

    return compatible(proxy, event)
  }

createProxy函數最後返回的是一個compatible函數的執行,在以前分析$.Event就有遇到過,在這裏來分析其做用。flex

function compatible(event, source) {
//若是沒有傳入source函數而且evnet事件阻止了默認操做,則直接返回傳入的event參數
if (source || !event.isDefaultPrevented) { source || (source = event) $.each(eventMethods, function(name, predicate) { var sourceMethod = source[name] event[name] = function(){ this[predicate] = returnTrue return sourceMethod && sourceMethod.apply(source, arguments) } event[predicate] = returnFalse }) event.timeStamp || (event.timeStamp = Date.now()) //對其默認操做進行相關判斷 if (source.defaultPrevented !== undefined ? source.defaultPrevented : 'returnValue' in source ? source.returnValue === false : source.getPreventDefault && source.getPreventDefault()) event.isDefaultPrevented = returnTrue } return event }

 

該函數最主要的代碼在中間的$.each(...),能夠先看一下eventMethods的定義
this

eventMethods = {
        preventDefault: 'isDefaultPrevented',
        stopImmediatePropagation: 'isImmediatePropagationStopped',
        stopPropagation: 'isPropagationStopped'
      }

在原生的事件屬性中,也存在prereventDefault等方法以及判斷其值的defaultPrevented屬性,但在zepto中,每次綁定事件,實際上都至關於從新定義一個事件,而自我定義的屬性是不具有prereventDefault等方法的功能,那麼defaultPrevented的值也就失效了。如圖:spa

function test2(e){
    var evt = {};
    for(key in evt)
        evt[key] = e[key];
    evt.preventDefault();
};
var box2 = document.getElementsByClassName('in')[0];
box2.addEventListener("click",test2);

因此compatible函數的做用就是爲了使原生事件preventDefault等的方法以及判斷其值的屬性轉變爲一個方法來使用。code

delegator函數中,最後返回的是對綁定函數的執行。

最後on方法執行了一個add()函數,該函數留在下一篇分析。

相關文章
相關標籤/搜索