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 新浪网易的评论块制作
Jul 01 Javascript
自定义jQuery选项卡插件实例
Mar 27 Javascript
jQuery点击弹出下拉菜单的小例子
Aug 01 Javascript
判断iframe里的页面是否加载完成
Jun 06 Javascript
jquery跟随屏幕滚动效果的实现代码
Apr 13 Javascript
分享一个精简的vue.js 图片lazyload插件实例
Mar 13 Javascript
jQuery EasyUI 为Combo,Combobox添加清除值功能的实例
Apr 13 jQuery
令按钮悬浮在(手机)页面底部的实现方法
May 02 Javascript
JavaScript实现鼠标滚轮控制页面图片切换功能示例
Oct 14 Javascript
Weex开发之WEEX-EROS开发踩坑(小结)
Oct 16 Javascript
解决vue-cli项目开发运行时内存暴涨卡死电脑问题
Oct 29 Javascript
解决vue无法侦听数组及对象属性的变化问题
Jul 17 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
php mail to 配置详解
2014/01/16 PHP
按给定几率进行随机抽取的js代码
2010/12/28 Javascript
JavaScript格式化日期时间的方法和自定义格式化函数示例
2014/04/04 Javascript
JSON+HTML实现国家省市联动选择效果
2014/05/18 Javascript
JQ技术实现注册页面带有校验密码强度
2015/07/27 Javascript
jQuery实现图片轮播特效代码分享
2015/09/15 Javascript
浅析node连接数据库(express+mysql)
2015/11/30 Javascript
解决js函数闭包内存泄露问题的办法
2016/01/25 Javascript
浅谈Javascript数据属性与访问器属性
2016/07/26 Javascript
jQuery监听文件上传实现进度条效果的方法
2016/10/16 Javascript
jQuery Easy UI中根据第一个下拉框选中的值设置第二个下拉框是否可以编辑
2016/11/29 Javascript
jquery实现百叶窗效果
2017/01/12 Javascript
vue webpack打包优化操作技巧
2018/02/22 Javascript
解决layer.open弹出框不能获取input框的值为空的问题
2019/09/10 Javascript
基于vue+echarts 数据可视化大屏展示的方法示例
2020/03/09 Javascript
[05:24]TI9采访——教练
2019/08/24 DOTA
Python的Flask框架与数据库连接的教程
2015/04/20 Python
python实现在每个独立进程中运行一个函数的方法
2015/04/23 Python
python下setuptools的安装详解及No module named setuptools的解决方法
2017/07/06 Python
python email smtplib模块发送邮件代码实例
2018/04/26 Python
python二维键值数组生成转json的例子
2019/12/06 Python
Python 实现使用空值进行赋值 None
2020/03/12 Python
Python定义函数实现累计求和操作
2020/05/03 Python
python简单利用字典破解zip文件口令
2020/09/07 Python
记录一下scrapy中settings的一些配置小结
2020/09/28 Python
如何通过python计算圆周率PI
2020/11/11 Python
微信浏览器取消缓存的方法
2015/03/28 HTML / CSS
安全的后院和健身蹦床:JumpSport
2019/07/15 全球购物
美国厨房和园艺工具网上商店:Nestneed
2019/08/24 全球购物
经济实惠的名牌太阳镜和眼镜:Privé Revaux
2021/02/07 全球购物
力学专业毕业生自荐信
2013/11/17 职场文书
现场施工员岗位职责
2014/03/10 职场文书
法律系毕业生自荐信范文
2014/03/27 职场文书
建筑工地质量标语
2014/06/12 职场文书
MySQL之DML语言
2021/04/05 MySQL
vue中的可拖拽宽度div的实现示例
2022/04/08 Vue.js