能够深入理解zepto对事件的处理,那么整个JS的事件处理就应该差不多合格了,事件处理是JS语言的一个难点。

1. 首先来看$.event函数

JS中有很多事件,都是已经定义好了,我们直接调用就可以,例如熟悉的click事件,直接对dom绑定一个事件,点击该dom就能触发这个事件,但是有这样的场景:我点击一个dom,重新打开一个页面。按照常规,可以通过window.open来执行,也可以模拟一个连接,在这个链接上绑定click,之后触发这个click事件。代码如下:

var a = document.createElement("a");
a.setAttribute("href", url);
a.setAttribute("target", "_blank");
a.setAttribute("id", "openwin");
document.body.appendChild(a);
//模拟点击事件
var m = document.createEvent("MouseEvents"); //FF的处理
m.initEvent("click", true, true);
a.dispatchEvent(m);

在zepto.js的ajax源码中,有很多注册事件,这些事件都是通过下来代码来完成的。

function triggerAndReturn(context, eventName, data) {
//步骤1:注册事件
var event = $.Event(eventName)
//步骤2:分发事件
$(context).trigger(event, data)
return !event.defaultPrevented
}
在注册和分发事件中,有三个步骤,对于与三个函数:
document.createEvent()  //新建
event.initEvent() //初始化
this.dispatchEvent() //元素触发事件

来看看$.event源码:

$.Event = function(type, props) {
if (!isString(type)) props = type, type = props.type
//click,mousedown,mouseup,mousemove的事件是MouseEvents,其他的是Events。
var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
//event.initEvent(eventType,canBubble,cancelable)
//eventType 字符串值。事件的类型。
//canBubble 事件是否起泡。
//cancelable 是否可以用 preventDefault() 方法取消事件。把bubbles从props中过滤出来,单独处理。
if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
event.initEvent(type, bubbles, true)
return compatible(event)
} /*
stopImmediatePropagation方法作用在当前节点以及事件链上的所有后续节点上。
目的是在执行完当前事件处理程序之后,停止当前节点以及所有后续节点的事件处理程序的运行。
stopPropagation方法作用在后续节点上,目的在执行完绑定到当前元素上的所有事件处理程序之后,停止执行所有后续节点的事件处理程序
*/
eventMethods = {
preventDefault: 'isDefaultPrevented',
stopImmediatePropagation: 'isImmediatePropagationStopped',
stopPropagation: 'isPropagationStopped'
}
function compatible(event, source) {
if (source || !event.isDefaultPrevented) {
source || (source = event)
/*
给event注册6个函数,默认[isDefaultPrevented,isImmediatePropagationStopped,isPropagationStopped] = false,
执行preventDefault之后,对应的preventDefault = {return true;}
*/
$.each(eventMethods, function(name, predicate) {
var sourceMethod = source[name]
event[name] = function(){
this[predicate] = returnTrue
return sourceMethod && sourceMethod.apply(source, arguments)
}
event[predicate] = returnFalse
})
//给isDefaultPrevented赋值
if (source.defaultPrevented !== undefined ? source.defaultPrevented :
'returnValue' in source ? source.returnValue === false :
source.getPreventDefault && source.getPreventDefault())
event.isDefaultPrevented = returnTrue
}
return event
}

再来看看$.trigger事件:

function fix(event) {
if (!('defaultPrevented' in event)) {
event.defaultPrevented = false
var prevent = event.preventDefault
//通过preventDefault取消事件的触发。
event.preventDefault = function() {
this.defaultPrevented = true
prevent.call(this)
}
}
}
$.fn.trigger = function(event, data){
if (typeof event == 'string') event = $.Event(event)
//添加preventDefaulted成员和重载preventDefault事件。
fix(event)
event.data = data
return this.each(function(){
//是dom节点都会有dispatchEvent事件,不是dom,如果有dispatchEvent事件也会执行。
if('dispatchEvent' in this) this.dispatchEvent(event)
})
}

还有一个triggerHandler事件,它与trigger有四个不同点:

  1. 它不会引起事件(比如表单提交)的默认行为
  2. trigger() 会操作 jQuery 对象匹配的所有元素,而 .triggerHandler() 只影响第一个匹配元素。
  3. 由 .triggerHandler() 创建的事件不会在 DOM 树中冒泡;如果目标元素不直接处理它们,则不会发生任何事情。
  4. 该方法的返回的是事件处理函数的返回值,而不是具有可链性的 jQuery 对象。此外,如果没有处理程序被触发,则这个方法返回 undefined。

这个后面我们再讨论。

2.事件对象

  用JS原生态的绑定事件很easy,而zepto对绑定事件进行重重封装,最明显的莫过于event对象,常规绑定事件。

    //每个element都有一个_zid来判断该element上已经绑定了几个事件。
var id = zid(element),
set = (handlers[id] || (handlers[id] = []))
eachEvent(events, fn, function(event, fn){
//如果没有事件委托,add只有element, events, fn三个参数
//element: 元素节点 events=["click","mouseup"...]
//fn:函数名或者匿名函数。
var delegate = getDelegate && getDelegate(fn, event),
callback = delegate || fn
var proxyfn = function (event) {
var result = callback.apply(element, [event].concat(event.data))
//callback返回为false,阻止默认事件。
if (result === false) event.preventDefault()
return result
}
/*
event = {
e: 事件名称
ns: 事件命名空间的对象
data: 参数
}
*/
var handler = $.extend(parse(event),
{
fn: fn,
proxy: proxyfn,
sel: selector,
del: delegate,
i: set.length
})
set.push(handler)
element.addEventListener(handler.e, proxyfn, capture)
})
}

委托绑定事件:

$.fn.delegate = function(selector, event, callback){
//委托事件不需要冒泡到父节点,只针对特定元素。
var capture = false
if(event == 'blur' || event == 'focus'){
if($.iswebkit)
event = event == 'blur' ? 'focusout' : event == 'focus' ? 'focusin' : event
else
capture = true
}
return this.each(function(i, element){
add(element, event, callback, selector, function(fn){
return function(e){
var evt,
match = $(e.target).closest(selector, element).get(0)
//匹配到特定的元素
if (match) {
evt = $.extend(createProxy(e),
{ currentTarget: match,
liveFired: element
})
return fn.apply(match, [evt].concat([].slice.call(arguments, 1)))
}
}
}, capture)
})
}

还有一种绑定事件,只绑定一次,

$.fn.one = function(event, callback){
return this.each(function(i, element){
//没有子元素选择参数
add(this, event, callback, null, function(fn, type){
return function(){
var result = fn.apply(element, arguments)
//触发之后,删除该事件。
remove(element, type, fn)
return result
}
})
})

 

zepto.js的事件处理的更多相关文章

  1. 学习zepto.js(对象方法)[5]

    继续说. clone: 该方法不接收任何参数,会返回对象中的所有元素集合,但不会对象绑定的事件. var $temp = $("div").clone(); //并不接收任何参数. ...

  2. 学习zepto.js(对象方法)[3]

    继续说zepto里attributes的相关操作. attr,removeAttr,prop这三个方法. attr(): 三种用途 get: 返回值为一个string字符串 $("<s ...

  3. 将jquery.shCircleLoader插件修改为zepto.js兼容

    经过查阅资料zepto 和 jquery 的区别后发现是 (1)zepto.js  删去了 jquery 的 innerHeight() 和 innerWidth() 属性  (2)zepto.js和 ...

  4. scroll事件实现监控滚动条并分页显示示例(zepto.js)

    scroll事件实现监控滚动条并分页显示示例(zepto.js  ) 需求:在APP落地页上的底部位置显示此前其他用户的购买记录,要求此div盒子只显示3条半,但一页有10条,div内的滑动条滑到一页 ...

  5. 学习zepto.js(Hello World)

    Zepto是一个轻量级的针对现代高级浏览器的JavaScript库, 它与jquery有着类似的api. 如果你会用jquery,那么你也会用zepto. 昨天听说了zepto.js,正好最近也比较闲 ...

  6. Zepto.js touch模块深入分析

    目的:记录 Zepto.js touch模块 源码阅读 源码: // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely ...

  7. 使用backbone.js、zepto.js和trigger.io开发HTML5 App

    为了力求运行速度快.响应迅即,我们推荐使用backbone.js和zepto.js. 为了让这个过程更有意思,我们开发了一个小小的示例项目,使用CSS重置样式.Backbone.js和带转场效果的几个 ...

  8. 移动开发js库Zepto.js应用详解

    从哪里下载 Zepto 地址:http://zeptojs.com/ 中文版地址:http://www.css88.com/doc/zeptojs_api/ 这个问题看起来很蠢,从官网下载不就行了嘛! ...

  9. zepto.js + iscroll.js上拉加载 下拉加载的 移动端 新闻列表页面

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name ...

随机推荐

  1. ubuntu14.04 安装配置JDK1.7

    1,下载jdk-7u45-linux-x64.tar.gz 网址:http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downlo ...

  2. tab切换(修改)

    html代码: <div class="tabContent"> <ul class="tab clearFix"> <li cl ...

  3. Linux_Shell_输出重定向

      创建两个文件:touch 1  touch2  命令 > 文件  以覆盖的方式输出正确信息到文件或设备ls > 1 命令 >> 文件 以追加的方式输出正确信息到文件或设备l ...

  4. 同 一个页面,不同请求路径,如何根据实际场景写JS

    场景:使用同一个“添加群成员”的页面来操作 建群页面:建群成功后,返回查看群成员页面.在建群过程中直接添加群成员并返回一个群名称的参数. 添加群成员页面:在巳有群内添加群成员,添加成功后,返回查看群成 ...

  5. hoj2662 状态压缩dp

    Pieces Assignment My Tags   (Edit)   Source : zhouguyue   Time limit : 1 sec   Memory limit : 64 M S ...

  6. js-判断字符是否为数字

    if(/^\d+$/.test(str)) { 全为数字,执行... } 当然你也可以用isNaN来判断 if(isNaN(str)) { str是个数字,执行... }

  7. XML和JSON的对比

    简介: 客户端和服务器之间进行数据交互时,服务器往往会返回给客户端一定格式的数据.一般而言,服务器返回给客户端的数据为JSON或者XML文档格式的数据(文件下载除外).下面就针对于这两种数据格式分别介 ...

  8. Leetcode 114, Flatten Binary Tree to Linked List

    根据提示,本题等价于pre order traverse遍历,并且依次把所有的节点都存成right child,并把left child定义成空集.用递归的思想,那么如果分别把左右子树flatten成 ...

  9. Leetcode 264. Ugly Number II

    Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors ...

  10. 【BZOJ-2115】Xor 线性基 + DFS

    2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2142  Solved: 893[Submit][Status] ...