第二十五课:jQuery.event.trigger的源码解读
本课主要来讲解jQuery.event.trigger的源码解读。
trigger = function(event, data, elem, onlyHandlers){
if(elem && (elem.nodeType === 3 || elem.nodeType ===8)){ //触发的元素节点不能是文本节点和注释节点
return;
}
var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, type = event.type || event , namespaces =[];
.....
if(type.indexOf(".") >= 0 ){ //如果事件类型带点号,就代表有命名空间,所以需要分解出命名空间
namespaces = type.split(".");
type = namespaces.shift();
namespaces.sort();
}
if((!elem || jQuery.event.customEvent [ type ]) && !jQuery.event.global[type]){ //如果元素不存在或者事件类型是自定义事件,并且之前从来没有绑定过此类型的事件,那么就直接返回。
return;
}
....
ontype = type.indexOf(":") < 0 ? "on" + type : ""; //如果事件类型没有:字符,就证明是ontype绑定事件
if(!elem){ //如果没有指明触发元素,就把整个缓存系统找一遍
cache = jQuery.cache;
for(i in cache){
if(cache[i].events && cache[i].events[ type ]){ //从缓存系统中,找相对应的events属性,并找到要触发事件类型的events[type]
jQuery.event.trigger(event,data,cache[i].handle.elem,true); //触发所有绑定了此事件类型的回调方法。
}
}
return; //直接返回
}
event.result = undefined;//清掉event的result属性,方便重复使用。
if(!event.target){
event.target = elem;
}
data = data!=null ? jQuery.makeArray(data) :[]; //如果传入了参数,就把参数转换成数组类型
data.unshift(event); //把事件对象放入数组的第一项
special = jQuery.event.special[type] || {}; //事件类型是否需要进行特殊化处理,比如:mousescroll事件
if(special.trigger && special.trigger.apply(elem,data) === false){ //如果事件类型已经有trigger方法,就调用它,如果返回结果是false,就直接返回。
return;
}
eventPath = [[elem, special.bindType || type]]; //规划冒泡的路径,从当前元素,一直到window
if(!onlyHandlers && !special.noBubble && !jQuery.isWindow(elem)){ //如果元素的事件类型没有阻止冒泡,并且元素不是window对象,就要进行冒泡模拟。
bubbleType = special.delegateType || type; //得到事件的类型
cur = elem.parentNode;
for(old = elem; cur ; cur = cur.parentNode){ //把当前元素的所有父元素,都进行一次事件类型的冒泡。假设div1(当前元素,触发click事件)上面有一个div2,div2上面有body,body上面有html,html上面有document。那么eventPath的数组是:[[div1,click],[div2,click],[body,click],[html,click],[document,click]]
eventPath.push([cur, bubbleType]);
old = cur;
}
if(old === (elem.ownerDocument || document)){ //当old为document时,cur为空,就退出循环
eventPath.push([old.defaultView || old.parentWindow || window, bubbleType]); //模拟冒泡到window对象
}
}
for(i=0;i<eventPath.length&&!event.isPropagationStopped(); i++){ //沿着上面规划好的冒泡路线,把经过的元素节点的指定类型事件的回调逐一触发执行
cur = eventPath[i][0]; //元素
event.type = eventPath[i][1] //事件类型
handle = (jQuery._data(cur,"events") || {})[event.type] && jQuery._data(cur,"handle");//先判断在缓存系统中是否有此元素绑定的此事件类型的回调方法,如果有,就取出来。
if(handle){ //执行这些回调方法
handle.apply(cur,data);
}
handle = ontype && cur[ontype]; //如果有onXXX绑定的回调,无论是写在js中,还是html标签内,都会取到
if(handle && jQuery.acceptData(cur) && handle.apply && handle.apply(cur, data) === false){//如果handle不为空,并且当前元素能绑定数据,并且handle有apply方法,就执行handle回调方法,如果当前回调返回false,就阻止默认事件。
event.preventDefault();
}
}
event.type = type;
if(!onlyHandlers && !event.isDefaultPrevented()){ //如果没有执行preventDefault方法,或上面的handle方法返回false(也会阻止默认事件)。就模拟默认行为。具体是指模拟:submit,blur,focus,select,reset,scroll等方法。
if((!special._default || special._default.apply(elem.ownerDocument,data) === false) && //如果用户指定了默认行为,就执行指定的默认行为,如果指定的默认行为返回false,就继续判断下面的条件
!(type === "click" && jQuery.nodeName(elem, "a"))&& //如果事件类型是click,并且是在a标签上触发的,就不执行它的默认行为了,否则继续判断
jQuery.acceptData(elem)){ //如果当前元素可以绑定数据
if(ontype && elem[type] && //如果元素有onXXX回调,并且元素有type方法,比如:<input type ="submit" onsubmit="function(){}">,它有onXXX的回调方法,也有input.submit的方法,因此继续判断
((type!=="focus" && type!=="blur") || event.target.offsetWidth !==0) && //如果事件类型不是focus,blur。或事件类型是focu,blur,但是触发这个事件的元素不是隐藏的(隐藏的元素,它的offsetWidth为0),就继续判断。(触发隐藏元素的focus和blur默认行为,IE6-8下会抛出错误。)
!jQuery.isWindow(elem)){ //不是window元素就进入if语句执行默认行为。(window的默认行为触发,会出现问题,比如:window.scroll方法,在IE与标准浏览器存在差异,IE会默认scroll()方法为scroll(0,0))
old = elem[ontype];
if(old){
elem[ontype] = null; //onXXX的回调已经执行过了,就不用再次执行了
}
jQuery.event.triggered = type; //标识正在触发此事件类型,防止下面的elem [ type ] ()重复执行dispatch方法
elem [ type ] (); //执行默认行为,比如:input[submit](),input元素的提交方法。点击类型为submint的input,会默认执行submit属性方法。但是这里不会调用dispatch方法。
jQuery.event.triggered = undefined; //还原
if(old){
elem[ontype] = old;
}
}
}
}
return event.result;
}
笼统来说,trigger就是dispatch的加强版。dispatch只触发当前元素与其底下元素(通过事件代理的方式)的回调。trigger则是模拟整个冒泡过程,除了它自身,还触发其祖先节点与window的同类型的回调。不过从trigger的代码来看,它比dispatch多做的事就是触发事件的默认行为。其实trigger要做的事就是在某一元素触发一个回调(dispatch),然后让它顺势冒泡,触发其他回调(dispatch)就行了。
浏览器提供了原生派发机制,IE下叫fireEvent,标准浏览器为dispatchEvent。IE下的问题是,有许多事件不能冒泡或不能冒泡到顶层,如果我们把IE的代码独立出来,标准浏览器用一套,IE用一套(旧版本IE,IE9在标准模式中支持dispatchEvent方法了),这样性能大大提高。zepto.js就是这么干的。
在创建万能事件对象时,理应document.createEvent("Events");但早期浏览器需要用document.createEvent("HTMLEvents");
万能事件理应能触发所有事件的回调,但是鼠标事件,要用MouseEvents参数创建鼠标对象事件才行。
火狐不支持mousewheel,我们需要用document.createEvent("MouseScrollEvents")创建DOMMouseScroll事件对象。
加油!
第二十五课:jQuery.event.trigger的源码解读的更多相关文章
- NeHe OpenGL教程 第二十五课:变形
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- 第二十五篇 jQuery 学习7 获取并设置 CSS 类
jQuery 学习7 获取并设置 CSS 类 jQuery动态控制页面,那么什么是动态呢?我们就说一下静态,静态几乎又纯html+css完成,就是刷新页面之后,不会再出现什么变动,一个实打实的静态 ...
- 树莓派开发笔记(十五):树莓派4B+从源码编译安装mysql数据库
前言 树莓派使用数据库时,优先选择sqlite数据库,但是sqlite是文件数据库同时仅针对于单用户的情况,考虑到多用户的情况,在树莓派上部署安装mysql服务,通过读写锁事务等使用,可以实现多进 ...
- 潭州课堂25班:Ph201805201 django 项目 第二十五课 文章多级评论前后台实现 (课堂笔记)
添加新闻评论功能 1.分析 业务处理流程: 判断前端传的新闻id是否为空,是否为整数.是否不存在 判断评论的内容是否为空 判断是否有父评论,父评论的id是否与新闻id匹配 判断用户是否登录 保存新闻评 ...
- python第二十五课——闭包
满足闭包的三个条件: 1).有外部函数和内部函数这样的结构 2).外部函数中定义的变量被内部函数所使用 3).内部函数对象作为返回值被外部函数返回 演示闭包的定义和使用: def outer(): a ...
- Spring入门第二十五课
使用具名参数 直接看代码: db.properties jdbc.user=root jdbc.password=logan123 jdbc.driverClass=com.mysql.jdbc.Dr ...
- JAVA学习第二十五课(多线程(四))- 单例设计模式涉及的多线程问题
一.多线程下的单例设计模式 利用双重推断的形式解决懒汉式的安全问题和效率问题 //饿汉式 /*class Single { private static final Single t = new Si ...
- Python学习第二十五课——Mysql (多表查询)
多表查询: 内连接查询: 首先:创建两个表一个为tableA,一个为tableB,并且插入数据(代码省略) 同时查询两个表的记录: select * from tableA,tableB; 根据tab ...
- jQuery scrollLeft()与scrollTop() 源码解读
这里的实现也很容易懂,通过jQuery的静态方法each给jQuery的原型添加scrollLeft和scrollTop方法. 这里在取值时它把window和普通的element做了区分 如果是win ...
随机推荐
- python 练习多级菜单思路
只写了一个zj的三级菜单,后面的功能没写 #-*- coding :utf-8 -*- print """ 你可以输入省份然后根据市县输入 ""&qu ...
- Memcache入门
说来惭愧,第一次听说Memcache是在大约在6个月前.作为一个搞J2EE开发的,工作一年多了,都没听说过Memcache实在是惭愧. 当时是换了新工作,第一个任务是开发一个报表系统供公司内部使用.为 ...
- leetcode抽风的解决办法
添加hosts: 173.230.148.103 oj.leetcode.com173.230.148.103 leetcode.com
- SQL SERVER 2012 使用订阅发布同步数据库
软件做大了,客户就多了,一个数据库服务器是远远不够的,当有一台数据服务器卦掉,那整个系统就会崩溃,所以必须考虑到数据库的自动同步与备份,当一台数据库服务 器宕机,自然就有用一台数据服务器启动起来保证整 ...
- jmap,jhat分析内存
分析JAVA Application的内存使用时,jmap是一个很实用的轻量级工具.使用jmap可以查看heap空间的概要情况,粗略的掌握heap的使用情况.也可以生成heapdump文件,再使用jh ...
- 快速理解Kafka分布式消息队列框架
作者:刘旭晖 Raymond 转载请注明出处 Email:colorant at 163.com BLOG:http://blog.csdn.net/colorant/ ==是什么 == 简单的说,K ...
- 《TCP/IP详解 卷一》读书笔记-----广播&多播&IGMP
1.广播和多播都只适用于UDP,因为TCP是面向连接的,需要将两台主机的两个进程绑定在一起,即IP地址和端口对 2.通常,网卡能看到网络中的每一个数据帧,但是往往它只接受目的地址与自己MAC地址相同的 ...
- [转]MySQL数据库的优化-运维架构师必会高薪技能,笔者近六年来一线城市工作实战经验
本文转自:http://liangweilinux.blog.51cto.com/8340258/1728131 年,嘿,废话不多说,下面开启MySQL优化之旅! 我们究竟应该如何对MySQL数据库进 ...
- 通过CDC获取 HDC
通过CDC获取HDC 通过CDC(设备描述表)获取HDC(设备上下文句柄)的方法: //第一种 void ...::OnDraw(CDC *pDC) { ...... HDC hDC=pDC-> ...
- Unity 2D Touch Movement
Demo试玩(Kongregate既然也有广告时间了 --!)http://www.kongregate.com/games/zhaoqingqing/2d-touch-movement 操作步骤 1 ...