能够深入理解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. nginx安装配置+清缓存模块安装

    经过一段时间的使用,发现nginx在并发与负载能力方面确实优于apache,现在已经将大部分站点从apache转到了nginx了.以下是nginx的一些简单的安装配置. 环境 操作系统:CentOS. ...

  2. EPUB书籍阅读器插件分享

    本文主要分享EPUB文件的打开方式, 包括如何使用火狐浏览器打开epub, 如何使用chrome打开epub, 如何使用IE浏览器打开epub文件: 1:使用火狐打开epub文件 如果有安装火狐浏览器 ...

  3. 写chrome插件---一个优酷自动加粉丝助手

    写chrome插件主要就是写js , 我们要构造界面(HTML), 以及样式(CSS),  以及chrome给我们提供的jsAPI, 主要是chrome的API, 调试的话可以使用chrome的开发者 ...

  4. JS中的事件类型和事件属性的基础知识

    周末无聊, 这几天又复习了下JS搞基程序设计3, 想着好记性不如浪笔头哇, 要么把这些东西写下来, 这样基础才能更加扎实么么哒, 知道的同学也可以直接过一下,当做复习,  小姨子再也不用担心我的学习啦 ...

  5. Jquery-pagination.js分页处理

    首先提供pagination.js的插件源码 /** * This jQuery plugin displays pagination links inside the selected elemen ...

  6. shell 题

    (1)有一推主机地址:a.baidu.com.....z.baidu.com如何从这些数据中提取出.baidu.com之前的字母,如:a b...z? #cat f1.txt | while read ...

  7. 【HDU 3746】Simpsons’ Hidden Talents(KMP求循环节)

    求next数组,(一般有两种,求循环节用的见代码)求出循环节的长度. #include <cstdio> #define N 100005 int n,next[N]; char s[N] ...

  8. bzoj1799: [Ahoi2009]self 同类分布

    数位dp 先从1到162枚举各位数之和 s[i][j][k][l]表示i位数,第一位小于等于j,当前各位数字和为k,当前取模余数为l的方案数 然后脑补一下转移就行了 详见代码 #include < ...

  9. 翻滚吧,Spark (错误记录)

    1) 本地运行报错: Exception in thread "main" org.apache.spark.SparkException: A master URL must b ...

  10. BZOJ 4385: [POI2015]Wilcze doły

    4385: [POI2015]Wilcze doły Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 648  Solved: 263[Submit][ ...