码迷,mamicode.com
首页 > 其他好文 > 详细

zepto源码分析------事件篇

时间:2015-03-28 22:57:17      阅读:1932      评论:0      收藏:0      [点我收藏+]

标签:

说说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更加复杂而已。

 

zepto源码分析------事件篇

标签:

原文地址:http://www.cnblogs.com/fctdream/p/4374891.html

(0)
(3)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!