jQuery的实现原理的模拟代码 -3 事件处理


Posted in Javascript onAugust 03, 2010

在对象的私有扩展对象上,专门增加了一个名为 events 的事件管理对象,在这个对象上每种事件分别对应一个同名的属性,这个属性的值是一个数组,针对这个事件的处理程序依次压入这个数组中,构成一个事件处理的列表。自定义的事件处理函数即被压入这个列表中。

在事件触发的时候,通过注册的匿名函数来执行 jQuery.event.handle ,由于使用了闭包,所以在这个函数中的 this 就是事件源对象,通过这个事件源对象找到对象的私有扩展数据,然后在 events 中找到对应的事件处理程序列表,最后,依次执行。

/// <reference path="jQuery-core.js" /> 
// #2076 
// 用于生成事件处理函数的 id 
jQuery.guid = 1; 
// jQuery 的事件对象 
jQuery.event = { // # 1555 
// 为对象增加事件 
// elem 增加事件的元素, type 事件的名称, handler 事件处理程序, data 事件相关的数据 
add: function (elem, type, handler, data) { 
var handleObjIn, handleObj; 
// 确认函数有一个唯一的 ID 
if (!handler.guid) { 
handler.guid = jQuery.guid++; 
} 
// 取得这个元素所对应的缓存数据对象 
var elemData = jQuery.data(elem); 
// 取得元素对应的缓存对象上的事件对象和所有事件共用的处理程序 
var events = elemData.events = elemData.events || {}; 
var eventHandle = elemData.handle; 
// 是否已经有事件处理函数 handle 只有一个,都是使用 jQuery.event.handle 
// 通过使用闭包,使得这个函数引用当前的事件对象,参数。 
if (!eventHandle) { 
elemData.handle = eventHandle = function () { 
return jQuery.event.handle.apply(eventHandle.elem, arguments); 
}; 
} 
// 使得闭包处理程序可以找到事件源对象 
eventHandle.elem = elem; 
// 
handleObj = { handler: handler, data: data}; 
handleObj.namespace = ""; handleObj.type = type; 
handleObj.guid = handler.guid; 
// 每种事件可以有一系列的处理程序,数组形式 
var handlers = events[type], 
special = jQuery.event.special[type] || {}; 
// Init the event handler queue 
if (!handlers) { 
handlers = events[type] = []; 
// Check for a special event handler 
// Only use addEventListener/attachEvent if the special 
// events handler returns false 
// 完成实际的事件注册 
// 实际的事件处理函数是 eventHandle 
if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) { 
// Bind the global event handler to the element 
if (elem.addEventListener) { 
elem.addEventListener(type, eventHandle, false); 
} else if (elem.attachEvent) { 
elem.attachEvent("on" + type, eventHandle); 
} 
} 
} 
// 自定义的处理函数在一个堆栈中,以后 jQuery.event.handle 到这里找到实际的处理程序 
handlers.push(handleObj); 
// Nullify elem to prevent memory leaks in IE 
elem = null; 
}, 
global: {}, 
// 真正的事件处理函数, 
// 由于是通过 return jQuery.event.handle.apply(eventHandle.elem, arguments) 调用的 
// 所以,此时的 this 就是事件源对象,event 是事件参数 
handle: function (event) { // 1904 
var all, handlers, namespaces, namespace, events; 
event = window.event; 
event.currentTarget = this; 
// 在当前的事件对象上找到事件处理列表 
var events = jQuery.data(this, "events"), handlers = events[event.type]; 
if (events && handlers) { 
// Clone the handlers to prevent manipulation 
handlers = handlers.slice(0); 
for (var j = 0, l = handlers.length; j < l; j++) { 
var handleObj = handlers[j]; 
// 取得注册事件时保存的参数 
event.handler = handleObj.handler; 
event.data = handleObj.data; 
event.handleObj = handleObj; 
var ret = handleObj.handler.apply(this, arguments); 
} 
} 
return event.result; 
}, 
// #2020 
special: {} 
} 
// bind 函数定义 
jQuery.fn.bind = function( type, fn) 
{ 
var handler = fn; 
// 调用 jQuery.event.add 添加事件 
for (var i = 0, l = this.length; i < l; i++) { 
jQuery.event.add(this[i], type, handler); 
} 
return this; 
} 
jQuery.fn.unbind = function (type, fn) { 
// Handle object literals 
if (typeof type === "object" && !type.preventDefault) { 
for (var key in type) { 
this.unbind(key, type[key]); 
} 
} else { 
for (var i = 0, l = this.length; i < l; i++) { 
jQuery.event.remove(this[i], type, fn); 
} 
} 
return this; 
} 
// click 事件的注册方法 
jQuery.fn.click = function (fn) { 
this.bind("click", fn); 
return this; 
}

这样,对于页面上的 id 为 msg 的元素,就可以通过下面的代码注册一个 click 事件处理函数。

// 事件操作 
$("#msg").click( 
function () { 
alert(this.innerHTML); 
} 
);
Javascript 相关文章推荐
使用jQuery向asp.net Mvc传递复杂json数据-ModelBinder篇
May 07 Javascript
JavaScript 高级篇之闭包、模拟类,继承(五)
Apr 07 Javascript
javascript jq 弹出层实例
Aug 25 Javascript
Node.js文件操作详解
Aug 16 Javascript
jquery事件的ready()方法使用详解
Nov 11 Javascript
JS中setTimeout的巧妙用法前端函数节流
Mar 24 Javascript
jQuery中使用animate自定义动画的方法
May 29 Javascript
js css+html实现简单的日历
Jul 14 Javascript
原生js实现移动端触摸轮播的示例代码
Dec 22 Javascript
Vue 页面切换效果之 BubbleTransition(推荐)
Apr 08 Javascript
vue 实现走马灯效果
Oct 28 Javascript
antd-DatePicker组件获取时间值,及相关设置方式
Oct 27 Javascript
SlideView 图片滑动(扩展/收缩)展示效果
Aug 01 #Javascript
JavaScript和ActionScript的交互实现代码
Aug 01 #Javascript
JavaScript判断窗口是否最小化的代码(跨浏览器)
Aug 01 #Javascript
jquery下onpropertychange事件的绑定方法
Aug 01 #Javascript
关于this和self的使用说明
Aug 01 #Javascript
ajax 缓存 问题 requestheader
Aug 01 #Javascript
parseInt parseFloat js字符串转换数字
Aug 01 #Javascript
You might like
奉献出一个封装的curl函数 便于调用(抓数据专用)
2013/07/22 PHP
PHP远程调试之XDEBUG
2015/12/29 PHP
PHP 在数组中搜索给定的简单实例 array_search 函数
2016/06/13 PHP
zend框架实现支持sql server的操作方法
2016/12/08 PHP
基于yaf框架和uploadify插件,做的一个导入excel文件,查看并保存数据的功能
2017/01/24 PHP
如何优雅的使用 laravel 的 validator验证方法
2018/11/11 PHP
Laravel框架基于ajax和layer.js实现无刷新删除功能示例
2019/01/17 PHP
Yii Framework框架使用PHPExcel组件的方法示例
2019/07/24 PHP
jQuery中:last选择器用法实例
2014/12/30 Javascript
JS时间特效最常用的三款
2015/08/19 Javascript
理解javascript正则表达式
2016/03/08 Javascript
用Vue.js实现监听属性的变化
2016/11/17 Javascript
使用snowfall.jquery.js实现爱心满屏飞的效果
2017/01/05 Javascript
JavaScript中创建对象的7种模式详解
2017/02/21 Javascript
微信分享调用jssdk实例
2017/06/08 Javascript
Vue项目安装插件并保存
2019/01/28 Javascript
JS猜数字游戏实例讲解
2020/06/30 Javascript
js实现简易ATM功能
2020/10/27 Javascript
Vue2.x-使用防抖以及节流的示例
2021/03/02 Vue.js
使用C#配合ArcGIS Engine进行地理信息系统开发
2016/02/19 Python
python模块导入的细节详解
2018/12/10 Python
python远程调用rpc模块xmlrpclib的方法
2019/01/11 Python
python中提高pip install速度
2020/02/14 Python
Python实现猜年龄游戏代码实例
2020/03/25 Python
python中openpyxl和xlsxwriter对Excel的操作方法
2021/03/01 Python
美国眼镜网站:EyeBuyDirect
2017/04/13 全球购物
Nicole Miller官方网站:纽约女装品牌
2019/09/14 全球购物
介绍一下Python下range()函数的用法
2013/11/07 面试题
咨询公司各岗位职责
2013/12/02 职场文书
青年志愿者先进事迹
2014/05/06 职场文书
十佳护士先进事迹
2014/05/08 职场文书
幸福家庭标语
2014/06/27 职场文书
导游词之吉林花园山
2019/10/17 职场文书
SQLServer2019 数据库的基本使用之图形化界面操作的实现
2021/04/08 SQL Server
MySQL 全文索引使用指南
2021/05/25 MySQL
Mysql 如何实现多张无关联表查询数据并分页
2021/06/05 MySQL