• zepto 事件分析3(add函数)


    在上一篇的分析中,最后$.on方法返回了一个add方法函数的执行,在这里先看一下其代码:

    function add(element, events, fn, data, selector, delegator, capture){
        var id = zid(element), set = (handlers[id] || (handlers[id] = []))
        events.split(/s/).forEach(function(event){
          if (event == 'ready') return $(document).ready(fn)
          var handler   = parse(event)
          handler.fn    = fn
          handler.sel   = selector
          console.log(handler.e)
          // emulate mouseenter, mouseleave
          if (handler.e in hover) fn = function(e){
            var related = e.relatedTarget
            if (!related || (related !== this && !$.contains(this, related)))
              return handler.fn.apply(this, arguments)
          }
          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))
        })
      }

    在这里先跳过id以及handler部分(handler.e的值即为事件的type属性),该函数主要作用就是将事件添加进元素的事件队列里。

    首先是对events进行分割成多个事件,并通过each函数逐个绑定。先来看一下函数里面的条件判定:

    hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
    if
    (handler.e in hover) fn = function(e){ var related = e.relatedTarget if (!related || (related !== this && !$.contains(this, related))) return handler.fn.apply(this, arguments) }

    如果事件的type属性是mouseenter或者mouseleave,那么需要重新定义绑定函数fn,什么是relatedTarget呢?

    relatedTarget 属性用于在一个事件中查找另外一个元素。有些事件比如 mouseover 通常侧重处理一个特定的目标,而有些有也可能会涉及到第二目标,比如当目标退出第一目标的 mouseover 事件.

    获得relatedTarget元素后,zepto对其进行判断,if (!related || (related !== this && !$.contains(this, related))),假设我们有两个div。

    <div class="out">
        <div class="in"></div>
    </div>

    我们对div.out定义mouseenter事件后,当我们鼠标从div.in移出来,但鼠标仍然在div.out,那么鼠标自始至终都在div.out中,但还是触发了mouseenter事件,这可能与预期中不同,所以zepto在这里加了判断,如果relatedTarget元素不存在,或者relatedTarget元素不是我们想要触发的元素本身,并且不包含在其中,即返回一个调用原来的fn函数。

    接下来就是handler.proxy函数了,该函数的作用就是通过apply调用绑定的事件函数,并返回结果。

    最后通过原生addEvent来绑定函数。

    最后,总结一下zepto中绑定事件的思路:

    1.找到目标元素。 即match = $(e.target).closest(selector, element).get(0),如果没有selector即跳过。

    2.事件委托。如果存在selector,即重新生成一个事件,并通过compitable,createProxy对其进行修改,并改变其currentTarget属性,如果不存在selector,即对要绑定的dom执行compitable,添加eventMethod中的方法。

    3.事件绑定,当存在selector触发时,实际触发的是$对象中的dom元素,只是通过事件委托使得像在符合selector条件元素中执行一样。

    ps:当存在selector时,假设绑定了click事件,但点击的是$对象中的dom元素并且区域不在selector中,同样触发了事件对象,只是上一篇中的delegator函数里,如果找不到selector,那么跳过,不执行我们绑定的函数。$中的dom元素绑定的是handler.proxy函数,handler.proxy返回的是delegator的执行结果,而delegator如果找不到selector,那么就不执行我们绑定的函数。

  • 相关阅读:
    记录操作:增删改查
    mysql表的完整性约束
    mysql支持的数据类型:数值类型、时间类型、字符串类型、ENUM和SET类型
    mysql中的存储引擎
    系统从未分库分表动态切换到分库分表
    为什么要分库分表
    生产环境中的 redis 是怎么部署的
    redis 集群模式
    redis 的持久化方式
    redis 的过期策略都有哪些?内存淘汰机制都有哪些?
  • 原文地址:https://www.cnblogs.com/Darlietoothpaste/p/6613849.html
Copyright © 2020-2023  润新知