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 相关文章推荐
《JavaScript高级程序设计》阅读笔记(二) ECMAScript中的原始类型
Feb 27 Javascript
JS获取时间的方法
Jan 21 Javascript
JQuery实现防止退格键返回的方法
Feb 12 Javascript
jquery ui resize 中border-box的bug修正
Apr 26 Javascript
Node.js中的process.nextTick使用实例
Jun 25 Javascript
基于dropdown.js实现的两款美观大气的二级导航菜单
Sep 02 Javascript
jQuery日程管理插件fullcalendar使用详解
Jan 07 Javascript
详解使用angular-cli发布i18n多国语言Angular应用
May 20 Javascript
微信小程序对接七牛云存储的方法
Jul 30 Javascript
JS实现静态页面搜索并高亮显示功能完整示例
Sep 19 Javascript
关于vue的npm run dev和npm run build的区别介绍
Jan 14 Javascript
vue中h5端打开app(判断是安卓还是苹果)
Feb 26 Vue.js
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判断输入不超过mysql的varchar字段的长度范围
2011/06/24 PHP
PHP中echo,print_r与var_dump区别分析
2014/09/29 PHP
PHP中substr()与explode()函数用法分析
2014/11/24 PHP
php实现excel中rank函数功能的方法
2015/01/20 PHP
php实现将wav文件转换成图像文件并在页面中显示的方法
2015/04/21 PHP
CSS中一些@规则的用法小结
2021/03/09 HTML / CSS
mouse_on_title.js
2006/08/25 Javascript
javascript 混合的构造函数和原型方式,动态原型方式
2009/12/07 Javascript
Prototype源码浅析 Enumerable部分(二)
2012/01/18 Javascript
jquery怎样实现ajax联动框(一)
2013/03/08 Javascript
JS实现自动切换文字的导航效果代码
2015/08/27 Javascript
基于jquery fly插件实现加入购物车抛物线动画效果
2016/04/05 Javascript
jQuery模拟窗口抖动效果
2017/03/15 Javascript
JS获取子节点、父节点和兄弟节点的方法实例总结
2018/07/06 Javascript
浅析vue-router jquery和params传参(接收参数)$router $route的区别
2018/08/03 jQuery
jquery.pagination.js分页使用教程
2018/10/23 jQuery
详解微信图片防盗链“此图片来自微信公众平台 未经允许不得引用”的解决方案
2019/04/04 Javascript
基于JavaScript获取url参数2种方法
2020/04/17 Javascript
Vue+scss白天和夜间模式切换功能的实现方法
2021/01/05 Vue.js
Python中super关键字用法实例分析
2015/05/28 Python
Python简单实现Base64编码和解码的方法
2017/04/29 Python
Python中Threading用法详解
2017/12/27 Python
Python3.6笔记之将程序运行结果输出到文件的方法
2018/04/22 Python
Python运行不显示DOS窗口的解决方法
2018/10/22 Python
详解pandas中MultiIndex和对象实际索引不一致问题
2019/07/23 Python
Tensorflow中tf.ConfigProto()的用法详解
2020/02/06 Python
PyQt5事件处理之定时在控件上显示信息的代码
2020/03/25 Python
python如何删除文件、目录
2020/06/23 Python
Python 中如何使用 virtualenv 管理虚拟环境
2021/01/21 Python
open_basedir restriction in effect. 原因与解决方法
2021/03/14 PHP
机械电子工程毕业生自荐信
2013/11/23 职场文书
建筑经济管理专业求职信分享
2014/01/06 职场文书
《雨霖铃》教学反思
2014/02/22 职场文书
2014办公室副主任四风对照检查材料思想汇报
2014/09/20 职场文书
2014年仓库保管员工作总结
2014/12/03 职场文书
2015年医院药剂科工作总结
2015/05/04 职场文书