标签:
说说zepto.js的源码。今天先分析事件,我比较懒,前面的基础函数就不分析了。直接按模块写就可以了。
在分析之前先简单的说一下zepto的大致结构
var Zepto = (function{})() // 事件模块 (function($){})(zepto) //ajax模块 (function($){})(zepto) // form事件 (function($){})(zepto)
大致结构就是这样了;其实里面的函数也挺简单的,我们都知道zepto这个框架是专为移动端开发,可谓是短小精悍,当然貌似还有坑啊。那么对于事件我们就比较熟悉。在非ie下的事件绑定/移除是这样的
element.addEventListener(type.fn,false/true)
element.removeEventListener()
那就好办了。我们先说绑定。在这家伙的内部有个函数叫 add函数。这个是最终的绑定。我们来分析分析里面都有些什么东西?
function add(element, events, fn, data, selector, delegator, capture) { //为事件增加id var id = zid(element), // 判断事件对象里面是不是有了,有了就返回,没有就给个空数组 set = (handlers[id] || (handlers[id] = [])); // 我猜的话应该是 同一个对象可以绑定多种事件$(‘li‘).on("click hover") events.split(/\s/).forEach(function(event) { // 判断是不是ready事件如果是直接调ready函数行了 if (event == ‘ready‘) return $(document).ready(fn) // 命名空间处理 var handler = parse(event) // 绑回调 handler.fn = fn handler.sel = selector //handler Object {e: "clcik", ns: "", fn: function, sel: undefined} // 判定 mouseenter, mouseleave 如果是的话 对fn进行改变 if (handler.e in hover) fn = function(e) { // relatedTarget主要是mouseover和mouseout的属性 划入或者划出 var related = e.relatedTarget if (!related || (related !== this && !$.contains(this, related))) return handler.fn.apply(this, arguments) } // delegator不传的话就是undefinde handler.del = delegator var callback = delegator || fn handler.proxy = function(e) { e = compatible(e) // 取消事件传播 if (e.isImmediatePropagationStopped()) return e.data = data // 回调绑定 var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) if (result === false) e.preventDefault(), e.stopPropagation() return result } handler.i = set.length set.push(handler) if (‘addEventListener‘ in element) { element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) } }) }
add函数大致就是这样,里面有些参数暂时先不管,我们到后面看看,这些参数是干什么的。我们下面再继续看看如何解绑定
function remove(element, events, fn, selector, capture) { var id = zid(element); (events || ‘‘).split(/\s/).forEach(function(event) { findHandlers(element, event, fn, selector).forEach(function(handler) { delete handlers[id][handler.i] if (‘removeEventListener‘ in element) element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) }) }) }
解绑定就比较简单了。很明显在最后一句
element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
三个参数都是我们刚才在add函数里面生成的。现在讲解里面的技术点 var id = zid(element)这个其实是为每一个回调生成了一个id这样方便在删除的时候找到他。然后就是handler其实就是一个空的字面量对象,在里面添加一个配置属性。这个的话我们就可以通过hendler去操作这个事件的一些属性了;好吧,基础函数我们先告一段落,我们下面来看看on这种事件是怎么处理
// 写法和jquery一样啊 还是以on为基准 on用于参数调整 add用于真正绑定 $.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 } /*下面都是在调正位置*/ // 选择器不存在 回调不存在 if (!isString(selector) && !isFunction(callback) && callback !== false) callback = data, data = selector, selector = undefined // data是函数或者data是false if (isFunction(data) || data === false) callback = data, data = undefined // 如果回调返回false if (callback === false) callback = returnFalse //上面都是非正常情况下。下面是我们常用的情况 return $this.each(function(_, element) { // _是索引 element是对象 // one存在在情况下 if (one) autoRemove = function(e) { remove(element, e.type, callback) return callback.apply(this, arguments) } // 选择器存在 if (selector) delegator = function(e) { // 获取目标元素 var evt, match = $(e.target).closest(selector, element).get(0) if (match && match !== element) { // 设定事件对象 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) }) }
这里面其实有两个技术点第一位置的调整,因为api很灵活那么将会导致有些参数根本不存在,那么就会进行参数的调整。第二。api中有这么一个东西on(tyle,select,xx,xx,xx);好的。用的同学都知道这是对绑定元素的扩展绑定(不知道怎么去表达,反正就是缩小范围嘛)那么这个是怎么实现的呢?我们会注意到,在on函数里面有个东西 if (selector) delegator = function(e) {}其实这个已经对你绑定的对象进行了悄无声息的改变。然后调用add函数,一切搞定。
好吧,今天就到这里了。我说一下大致的思路,其实就是以add remove为顶层函数,然后on/off为较低层函数。至于bind这些函数是建立在on/off之上的。而on/off又是建立在add/remove之上。on/off只是起了一个简单的参数调整的作用。
看过query源码的同学应该也会发现,其实这些框架的实现方法都差不多,只是jquery更加复杂而已。
标签:
原文地址:http://www.cnblogs.com/fctdream/p/4374891.html