能够深入理解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. Linux服务器配置git服务

    前言 Git是一个非常著名的分布式版本控制系统,而广大开发者更是习惯在最大的远程仓库GitHub上提交自己的代码.但是有时候,一些小项目不值得放到GitHub上去,或是由于隐私问题不好在GitHub的 ...

  2. javascript获得客户端IP的又一方法

    <script language="JavaScript">VIH_BackColor = "palegreen";VIH_ForeColor = ...

  3. 【NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2】游记

    我第一次写游记,,,, 正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪 ...

  4. 【POJ 3415】Common Substrings 长度不小于k的公共子串的个数

    长度不小于k的公共子串的个数,论文里有题解,卡了一上午,因为sum没开long long!!! 没开long long毁一生again--- 以后应该早看POJ里的Discuss啊QAQ #inclu ...

  5. JavaScript的DOM操作-重点部分-第一部分

    Window.document 对象 一.找到元素 document.getElementById("id"); 根据id找,最多找一个: var a = document.get ...

  6. Leetcode House Robber II

    本题和House Robber差不多,分成两种情况来解决.第一家是不是偷了,如果偷了,那么最后一家肯定不能偷. class Solution(object): def rob(self, nums): ...

  7. 【caffe】create_cifar10.sh在windows下解决方案

    @tags caffe python windows下配置caffe后,create_cifar10.sh无法执行,因为是shell脚本.那就看懂脚本意思,用python重写一个: # create_ ...

  8. 安装vmall5:从ebak恢复数据,需要配置php.ini

    上传vmall5源码到服务器后访问ebak目录,发现网页不显示.用xshell登录到服务器手动执行ebak/index.php查看输出,发现这样一个错误: PHP Parse Error: synta ...

  9. 【BZOJ-4059】Non-boring sequences 线段树 + 扫描线 (正解暴力)

    4059: [Cerc2012]Non-boring sequences Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 440  Solved: 16 ...

  10. 设置CentOS6.5时钟同步

    一.测试ntp服务 # rpm -q ntp ntp-4.2.4p8-2.el6.x86_64 // 这表示已安装了,如果没有安装,这是空白. 二./etc/ntp.conf 红色部分是修改的. 配置 ...