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 相关文章推荐
ajax 文件上传应用简单实现
Mar 03 Javascript
jQuery方法简洁实现隔行换色及toggleClass的使用
Mar 15 Javascript
javascript模拟地球旋转效果代码实例
Dec 02 Javascript
jquery实现手机号码选号的方法
Jul 31 Javascript
jQuery插件之Tocify动态节点目录菜单生成器附源码下载
Jan 08 Javascript
AngularJS中使用ngModal模态框实例
May 27 Javascript
Vue2.0 vue-source jsonp 跨域请求
Aug 04 Javascript
Vue 路由切换时页面内容没有重新加载的解决方法
Sep 01 Javascript
vue+Element-ui实现分页效果实例代码详解
Dec 10 Javascript
Vue 刷新当前路由的实现代码
Sep 26 Javascript
VUE 动态组件的应用案例分析
Dec 02 Javascript
纯js+css实现在线时钟
Aug 18 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
2020年4月放送决定!第2期TV动画《邪神酱飞踢》视觉图&主题曲情报公开!
2020/03/06 日漫
PHP设计模式之观察者模式定义与用法分析
2019/04/04 PHP
JavaScript随机排序(随即出牌)
2010/09/17 Javascript
关于jQuery中的end()使用方法
2011/07/10 Javascript
Javascript根据指定下标或对象删除数组元素
2012/12/21 Javascript
浅谈checkbox的一些操作(实战经验)
2013/11/20 Javascript
javascript页面动态显示时间变化示例代码
2013/12/18 Javascript
jQuery Ajax()方法使用指南
2014/11/19 Javascript
jQuery插件datepicker 日期连续选择
2015/06/12 Javascript
JS 拦截全局ajax请求实例解析
2016/11/29 Javascript
简单的渐变轮播插件
2017/01/12 Javascript
JS实现JSON.stringify的实例代码讲解
2017/02/07 Javascript
js实现兼容PC端和移动端滑块拖动选择数字效果
2017/02/16 Javascript
JS中关于正则的巧妙操作
2017/08/31 Javascript
解决angular2 获取到的数据无法实时更新的问题
2018/08/31 Javascript
Django+vue跨域问题解决的详细步骤
2019/01/20 Javascript
生产制造追溯系统之再说条码打印
2019/06/03 Javascript
vue项目中使用AES实现密码加密解密(ECB和CBC两种模式)
2019/08/12 Javascript
Python二维码生成库qrcode安装和使用示例
2014/12/16 Python
Python的字典和列表的使用中一些需要注意的地方
2015/04/24 Python
python中matplotlib实现最小二乘法拟合的过程详解
2017/07/11 Python
Pycharm 设置自定义背景颜色的图文教程
2018/05/23 Python
Python3中在Anaconda环境下安装basemap包
2018/10/21 Python
Python中时间datetime的处理与转换用法总结
2019/02/18 Python
通过实例了解Python异常处理机制底层实现
2020/07/23 Python
Pycharm创建文件时自动生成文件头注释(自定义设置作者日期)
2020/11/24 Python
美国最顶级的精品店之一:Hampden Clothing
2016/12/22 全球购物
澳大利亚墨水站Ink Station:墨水和碳粉打印机墨盒
2019/03/24 全球购物
泰国的头号网上婴儿用品店:Motherhood.co.th
2019/04/09 全球购物
LACOSTE波兰官网:Polo衫、服装和鞋类
2020/09/29 全球购物
房地产开盘策划方案
2014/02/10 职场文书
党员干部廉洁承诺书
2014/05/28 职场文书
大学生万能检讨书范例
2014/10/04 职场文书
2015年党风廉政建设目标责任书
2015/05/08 职场文书
详解MySQL 联合查询优化机制
2021/05/10 MySQL
Nginx流量拷贝ngx_http_mirror_module模块使用方法详解
2022/04/07 Servers