這裏主要分析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()函數,該函數留在下一篇分析。