彻底弄懂jQuery事件原理一
jQuery为我们提供了一个非常丰富好用的事件API,相对于浏览器自身的事件接口,jQuery有以下特点:
1. 对浏览器进行了兼容性处理,用户使用不需要考虑浏览器兼容性问题
2. 事件数据是保持在内部缓存中的,而不是保持在DOM节点上
3. 事件委托机制,提供了一个非常简单的事件委托使用方法
4. 自定义事件,不仅仅是浏览器事件,可以创建自定义事件
5. 辅助功能,比如命名空间,事件数据等等
那么下面就来看看jQuery是怎么实现的,首先扫一眼Event模块的源码结构:

总共900行,总共包括5部分:
1. 正则和辅助函数:最上面的正则表达式和3个辅助函数,后面会说到

2. event辅助类:用于事件处理的辅助对象

3. Event可写事件对象,等同于浏览器事件中的event对象,但Event对象的数据是可写的,添加了jQuery的一些属性。

4. 兼容性处理:事件的兼容性处理逻辑

5. 对外API,添加到jquery实例对象的对外API

这段代码结构逻辑上分为4层,
第一层是对外API,这段是对用户调用的参数处理
第二层是event辅助类,用户调用以后会调用辅助类的各种方法
第三层是Event对象,event处理过程中会创建Event对象来代替浏览器事件中的event对象
第四层是兼容性处理,针对浏览器中有些事件的兼容性问题,进行了处理
1. 我们从对外API开始说起,比如:
<div id='div_main'>
<div id="div_sub"></div>
</div> <script>
$("#div_main").on("click",function(){
console.log(1);
});
</script>
我们对$("#div_main")这个jquery对象调用了on方法,就可以注册一个点击事件,on方法是什么?见对外API那部分代码
on: function(types, selector, data, fn, /*INTERNAL*/ one) {
var origFn, type;
// Types can be a map of types/handlers
if (typeof types === "object") {
// ( types-Object, selector, data )
if (typeof selector !== "string") {
// ( types-Object, data )
data = data || selector;
selector = undefined;
}
for (type in types) {
this.on(type, selector, data, types[type], one);
}
return this;
}
if (data == null && fn == null) {
// ( types, fn )
fn = selector;
data = selector = undefined;
} else if (fn == null) {
if (typeof selector === "string") {
// ( types, selector, fn )
fn = data;
data = undefined;
} else {
// ( types, data, fn )
fn = data;
data = selector;
selector = undefined;
}
}
if (fn === false) {
fn = returnFalse;
} else if (!fn) {
return this;
}
if (one === ) {
origFn = fn;
fn = function(event) {
// Can use an empty set, since event contains the info
jQuery().off(event);
return origFn.apply(this, arguments);
};
// Use same guid so caller can remove using origFn
fn.guid = origFn.guid || (origFn.guid = jQuery.guid++);
}
return this.each(function() {
jQuery.event.add(this, types, fn, data, selector);
});
},
on
这段代码其实是对用户调用的方法进行了各种参数情况逻辑判断,最后归根到jQuery.event.add方法,也就是最后是调用了event辅助类的方法,首先on方法对用户传入的参数进行了判断,主要可能有以下几种情况:
(1) 以json方式传入多个事件方法,比如:
on({"click":fn1,"blur":fn2},"li",data);
on({"click":fn1,"blur":fn2},data);
//json对象格式
if (typeof types === "object") {
//selector不是字符串是数据,则重新设置数据变量,on({"click":fn1,"blur":fn2},data)
if (typeof selector !== "string") {
data = data || selector;
selector = undefined;
}
//对每个json属性递归调用on方法
for (type in types) {
this.on(type, selector, data, types[type], one);
}
return this;
}
(2)其他三种情况:on("click",fn) on("click","li",fn) on("click",data,fn)
if (data == null && fn == null) {
// 类似on("click",fn1),重置变量
fn = selector;
data = selector = undefined;
} else if (fn == null) {
if (typeof selector === "string") {
//类似on("click","li",fn)
fn = data;
data = undefined;
} else {
//类似on("click",data,fn);
fn = data;
data = selector;
selector = undefined;
}
}
//快捷方式,如果fn参数传入false,自动设置为false方法
if (fn === false) {
fn = returnFalse;
} else if (!fn) {
return this;
}
if (one === 1) {//只执行一次的方法,执行一次后删除本事件对象
origFn = fn;
fn = function(event) {
// Can use an empty set, since event contains the info
jQuery().off(event);
return origFn.apply(this, arguments);
};
// Use same guid so caller can remove using origFn
fn.guid = origFn.guid || (origFn.guid = jQuery.guid++);
}
return this.each(function() {//对每个jquery实例进行调用
jQuery.event.add(this, types, fn, data, selector);
});
然后是one方法,其实就是调用上面的on方法,带上one参数
one: function(types, selector, data, fn) {
return this.on(types, selector, data, fn, 1);
},
off方法,和on方法类似,针对输入参数的几种情况最终是调用了event辅助类的remove方法。
off: function(types, selector, fn) {
var handleObj, type;
if (types && types.preventDefault && types.handleObj) {
// ( event ) dispatched jQuery.Event
handleObj = types.handleObj;
jQuery(types.delegateTarget).off(
handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
handleObj.selector,
handleObj.handler
);
return this;
}
if (typeof types === "object") {
// ( types-object [, selector] )
for (type in types) {
this.off(type, selector, types[type]);
}
return this;
}
if (selector === false || typeof selector === "function") {
// ( types [, fn] )
fn = selector;
selector = undefined;
}
if (fn === false) {
fn = returnFalse;
}
return this.each(function() {
jQuery.event.remove(this, types, fn, selector);
});
},
tigger方法,最终是调用event辅助类的tigger方法
trigger: function(type, data) {
return this.each(function() {
jQuery.event.trigger(type, data, this);
});
},
triggerHandler方法,调用event类的方法
triggerHandler: function(type, data) {
var elem = this[0];
if (elem) {
return jQuery.event.trigger(type, data, elem, true);
}
}
tiggerHandler和tigger方法的区别是,triggerHandler只执行jQuery对象数组中的第一个对象,并且不执行冒泡,不执行浏览器默认事件。
彻底弄懂jQuery事件原理一的更多相关文章
- 彻底弄懂jQuery事件原理二
上一篇说到,我们在最外层API的on,off,tiggler,triggerHandler调用的是event方法的add,remove和tirgger方法,本篇就来介绍event辅助类 \ 先放个图, ...
- 彻底弄懂JS事件委托的概念和作用
一.写在前头 接到某厂电话问什么是事件代理的时候,一开始说addEventListener,然后他说直接绑定新的元素不会报dom不存在的错误吗?然后我就混乱了,我印象中这个方法是可以绑定新节点的 ...
- 一篇文章彻底弄懂Base64编码原理
在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇博文带领大家了解一下Base64的底层实现. Base64的由来 目前Base64已经成为网 ...
- 一篇文章彻底弄懂Base64编码原理(转载)
在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇博文带领大家了解一下Base64的底层实现. Base64的由来 目前Base64已经成为网 ...
- 弄懂goroutine调度原理
goroutine简介 golang语言作者Rob Pike说,"Goroutine是一个与其他goroutines 并发运行在同一地址空间的Go函数或方法.一个运行的程序由一个或更多个go ...
- 知识扩展——(转)一篇文章彻底弄懂Base64编码原理
在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇博文带领大家了解一下Base64的底层实现. 一.Base64的由来 目前Base64已经成 ...
- 彻底弄懂JS的事件冒泡和事件捕获(不推荐阅读)
由于搬去敌台了,好久没来博客园,今天无意中翻到有“误认子弟”的评论,这里特意做个说明. 本文中关于事件冒泡和事件捕获的描述和例子都是OK的,错就错在后面用jquery去展示了利用事件冒泡的例子有误,其 ...
- js进阶 12-2 彻底弄懂JS的事件冒泡和事件捕获
js进阶 12-2 彻底弄懂JS的事件冒泡和事件捕获 一.总结 一句话总结:他们是描述事件触发时序问题的术语.事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件.相反的,事件 ...
- 彻底弄懂HTTP缓存机制及原理-转载
首先附上原文地址,非常感谢博主大神的分享彻底弄懂HTTP缓存机制及原理 前言 Http 缓存机制作为 web 性能优化的重要手段,对于从事 Web 开发的同学们来说,应该是知识体系库中的一个基 ...
随机推荐
- RabbitMQ(转)
add by zhj: 如果用Python,那可以用celery,它是一个分布式任务队列,它的broker可以选择Rabbitmq/Redis/Mongodb等, celery通过Kombu这个lib ...
- 007-spring cache-缓存实现-02-springboot ehcahe3实现、springboot caffeine实现
一.springboot ehcahe3实现步骤 EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认CacheProvider.Ehcache是一种广泛 ...
- django基础之Ajax、分页、cookie与session
目录: Ajax之json Ajax简介 jquery实现的ajax js实现的ajax django分页器 COOKIE与SESSION 一.Ajax之json 1.什么是json? 定义: JSO ...
- 调试:Spring AOP执行过程
调试项目:https://github.com/1367356/laboratoryWeb 断点位置 点击查询:http://localhost:9002/queryNews?htmlid=15318 ...
- tar命令解压时如何去除目录结构及其解压到指定目录 (--strip-components N)
去除目录结构加上 --strip-components N 如: 压缩文件eg.tar 中文件信息为 src/src/src/eg.txt 运行 tar -xvf eg.tar --strip-com ...
- 20165324_mybash
20165324_mybash 实验要求 实验要求: 使用fork,exec,wait实现mybash 写出伪代码,产品代码和测试代码 发表知识理解,实现过程和问题解决的博客(包含代码托管链接) 背景 ...
- acdream1174 合并同类项
这题说的是 给出N,a[1]... a[N],还有M,b[1]... b[M]long long ans = 0;for(int i = 1; i <= N; i ++) for(int ...
- pyimage search研究
包括<软实力>的作者,类似 http://www.learnopencv.com/, 这次调查研究的 http://www.pyimagesearch.com 是一个独立的博客,作者是机器 ...
- 线程访问ui,托管
1.在类中声明 delegate void setDebugDelegate(string info);//线程访问textbox委托函数 private void setDebug(string i ...
- 关于函数strtok和strtok_r的使用要点和实现原理(二)【转】
本文转载自:http://astute11.blog.51cto.com/4404646/1334199 (一)中已经介绍了使用strtok函数的一些注意事项,本篇将介绍strtok的一个应用并引出s ...