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 DOM操作 基于命令改变页面
May 06 Javascript
鼠标事件延时切换插件
Mar 12 Javascript
ExtJS实现文件下载的方法实例
Nov 09 Javascript
经过绑定元素时会多次触发mouseover和mouseout事件
Feb 28 Javascript
超链接的禁用属性Disabled使用示例
Jul 31 Javascript
JavaScript中绑定事件的三种方式及去除绑定
Nov 05 Javascript
JavaScript限定范围拖拽及自定义滚动条应用(3)
May 17 Javascript
Angular2管道Pipe及自定义管道格式数据用法实例分析
Nov 29 Javascript
基于Vue开发数字输入框组件
Dec 19 Javascript
React为 Vue 引入容器组件和展示组件的教程详解
May 03 Javascript
JS代码简洁方式之函数方法详解
Jul 28 Javascript
解决nuxt页面中mounted、created、watch执行两遍的问题
Nov 05 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实现Session存储到Redis
2015/11/11 PHP
php array_values 返回数组的值实例详解
2016/11/17 PHP
php实现映射操作实例详解
2019/10/02 PHP
javascript cookie解码函数(兼容ff)
2008/03/17 Javascript
Jquery css函数用法(判断标签是否拥有某属性)
2011/05/28 Javascript
js获取图片大小的函数代码
2011/09/20 Javascript
通过Javascript创建一个选择文件的对话框代码
2012/06/16 Javascript
JavaScript定义类的几种方式总结
2014/01/06 Javascript
一些老手都不一定知道的JavaScript技巧
2014/05/06 Javascript
EasyUi combotree 实现动态加载树节点
2016/04/01 Javascript
jquery实现ajax加载超时提示的方法
2016/07/23 Javascript
Bootstrap的fileinput插件实现多文件上传的方法
2016/09/05 Javascript
实例分析浏览器中“JavaScript解析器”的工作原理
2016/12/12 Javascript
JavaScript 巧学巧用
2017/05/23 Javascript
vue移动端实现下拉刷新
2018/04/22 Javascript
微信小程序实现页面下拉刷新和上拉加载功能详解
2018/12/03 Javascript
js中的reduce()函数讲解
2019/01/18 Javascript
部署vue+Springboot前后端分离项目的步骤实现
2020/05/31 Javascript
轻松实现TensorFlow微信跳一跳的AI
2018/01/05 Python
python检测空间储存剩余大小和指定文件夹内存占用的实例
2018/06/11 Python
win8下python3.4安装和环境配置图文教程
2018/07/31 Python
Python实现平行坐标图的两种方法小结
2019/07/04 Python
pandas读取CSV文件时查看修改各列的数据类型格式
2019/07/07 Python
python多线程同步实例教程
2019/08/11 Python
python3实现elasticsearch批量更新数据
2019/12/03 Python
PyTorch中permute的用法详解
2019/12/30 Python
Made in Design英国:设计家具、照明、家庭装饰和花园家具
2019/09/24 全球购物
东南亚冒险旅行与活动:Adventoro
2019/10/16 全球购物
在Ajax应用中信息是如何在浏览器和服务器之间传递的
2016/05/31 面试题
水污染治理专业毕业生推荐信
2013/11/14 职场文书
主治医师岗位职责
2013/12/10 职场文书
财务工作个人求职的自我评价
2013/12/19 职场文书
剪彩仪式主持词
2014/03/19 职场文书
三月学雷锋活动总结
2014/06/26 职场文书
防邪知识进家庭活动方案
2014/08/26 职场文书
2014年机关党委工作总结
2014/12/11 职场文书