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 相关文章推荐
js比较和逻辑运算符的介绍
Mar 10 Javascript
JQuery筛选器全系列介绍
Aug 27 Javascript
深入剖析JavaScript中的枚举功能
Mar 06 Javascript
JavaScript实现的多个图片广告交替显示效果代码
Sep 04 Javascript
JS实现1000以内被3或5整除的数字之和
Feb 18 Javascript
AngularJS中isolate scope的用法分析
Nov 22 Javascript
node.js实现的装饰者模式示例
Sep 06 Javascript
React通过父组件传递类名给子组件的实现方法
Nov 13 Javascript
cordova入门基础教程及使用中遇到的一些问题总结
Nov 14 Javascript
微信小程序mpvue点击按钮获取button值的方法
May 29 Javascript
js中的this的指向问题详解
Aug 29 Javascript
vue监听浏览器原生返回按钮,进行路由转跳操作
Sep 09 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中的UNICODE 编码与解码
2013/06/29 PHP
PHP编译安装中遇到的两个错误和解决方法
2014/08/20 PHP
使用array_map简单搞定PHP删除文件、删除目录
2014/10/29 PHP
PHP计算指定日期所在周的开始和结束日期的方法
2015/03/24 PHP
mac系统下安装多个php并自由切换的方法详解
2017/04/21 PHP
PHP crc32()函数讲解
2019/02/14 PHP
PHP的new static和new self的区别与使用
2019/11/27 PHP
HTTP头隐藏PHP版本号实现过程解析
2020/12/09 PHP
JS 对象属性相关(检查属性、枚举属性等)
2015/04/05 Javascript
js实现分享到随页面滚动而滑动效果的方法
2015/04/10 Javascript
简介JavaScript中Math.cos()余弦方法的使用
2015/06/15 Javascript
JavaScript数组各种常见用法实例分析
2015/08/04 Javascript
JQuery实现的按钮倒计时效果
2015/12/23 Javascript
Jquery Easyui对话框组件Dialog使用详解(14)
2016/12/19 Javascript
Vue.js中对css的操作(修改)具体方式详解
2018/10/30 Javascript
Nodejs处理异常操作示例
2018/12/25 NodeJs
vant 时间选择器--开始时间和结束时间实例
2020/11/04 Javascript
JQuery+drag.js上传图片并且实现图片拖曳
2020/11/18 jQuery
[04:44]显微镜下的DOTA2第二期——你所没有注意到的细节
2014/06/20 DOTA
Python中的闭包实例详解
2014/08/29 Python
python通过get,post方式发送http请求和接收http响应的方法
2015/05/26 Python
python爬虫实现教程转换成 PDF 电子书
2017/02/19 Python
Python实现文件信息进行合并实例代码
2018/01/17 Python
浅谈Tensorflow由于版本问题出现的几种错误及解决方法
2018/06/13 Python
Python 忽略文件名编码的方法
2020/08/01 Python
Python基于callable函数检测对象是否可被调用
2020/10/16 Python
HTML块级标签汇总(小篇)
2016/07/13 HTML / CSS
韩国知名的家庭购物网站:CJmall
2016/08/01 全球购物
Street One瑞士:德国现代时装公司
2019/10/09 全球购物
英文自荐信
2013/12/15 职场文书
消防安全汇报材料
2014/02/08 职场文书
机械系毕业生求职信
2014/05/28 职场文书
幼儿园大班教师个人总结
2015/02/05 职场文书
入党宣誓仪式主持词
2015/06/29 职场文书
《詹天佑》教学反思
2016/02/20 职场文书
Python爬虫之爬取最新更新的小说网站
2021/05/06 Python