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的几种方法
Oct 23 Javascript
JS request函数 用来获取url参数
May 17 Javascript
jQuery提交表单ajax查询实例代码
Oct 07 Javascript
自定义的一个简单时尚js下拉选择框
Nov 20 Javascript
JavaScript实现拖拽元素对齐到网格(每次移动固定距离)
Nov 30 Javascript
Angular4学习教程之DOM属性绑定详解
Jan 04 Javascript
vue2.0模拟锚点的实例
Mar 14 Javascript
详解Angular6.0使用路由步骤(共7步)
Jun 29 Javascript
详解vue+webpack+express中间件接口使用
Jul 17 Javascript
使用vue-router与v-if实现tab切换遇到的问题及解决方法
Sep 07 Javascript
vue2中引用及使用 better-scroll的方法详解
Nov 15 Javascript
vue使用recorder.js实现录音功能
Nov 22 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+ajaxfileupload+jcrop插件完美实现头像上传剪裁
2014/06/09 PHP
php获取网页中图片、DIV内容的简单方法
2014/06/19 PHP
Zend Framework动作助手Url用法详解
2016/03/05 PHP
phalcon model在插入或更新时会自动验证非空字段的解决办法
2016/12/29 PHP
PHP+JS实现的实时搜索提示功能
2018/03/13 PHP
Yii1.1框架实现PHP极光推送消息通知功能
2018/09/06 PHP
如何让PHP编码更加好看利于阅读
2019/05/12 PHP
php7 新增功能实例总结
2020/05/25 PHP
向fckeditor编辑器插入指定代码的方法
2007/05/25 Javascript
combox改进版 页面原型参考dojo的,比网上jQuery的那些combox功能强,代码更小
2010/04/15 Javascript
javascript如何创建表格(javascript绘制表格的二种方法)
2013/12/10 Javascript
require.js深入了解 require.js特性介绍
2014/09/04 Javascript
Thinkphp模板没有解析直接原样输出的解决方法
2014/10/31 Javascript
JavaScript简单表格编辑功能实现方法
2015/04/16 Javascript
纯javascript模仿微信打飞机小游戏
2015/08/20 Javascript
JavaScript实现点击按钮直接打印
2016/01/06 Javascript
基于javascript实现动态显示当前系统时间
2016/01/28 Javascript
java中String类型变量的赋值问题介绍
2016/03/23 Javascript
js实现精确到秒的日期选择器完整实例
2016/04/30 Javascript
BootStrap使用popover插件实现鼠标经过显示并保持显示框
2016/06/23 Javascript
Vue.js系列之项目搭建(1)
2017/01/03 Javascript
select下拉框插件jquery.editable-select详解
2017/01/22 Javascript
AngularJS 限定$scope的范围实例详解
2017/06/23 Javascript
详解关于vue-area-linkage走过的坑
2018/06/27 Javascript
python-str,list,set间的转换实例
2018/06/27 Python
Python使用logging模块实现打印log到指定文件的方法
2018/09/05 Python
python中dict字典的查询键值对 遍历 排序 创建 访问 更新 删除基础操作方法
2018/09/13 Python
python添加模块搜索路径和包的导入方法
2019/01/19 Python
详解python破解zip文件密码的方法
2020/01/13 Python
解决python3.6用cx_Oracle库连接Oracle的问题
2020/12/07 Python
宝宝周岁宴答谢词
2014/01/26 职场文书
董事长助理岗位职责
2014/02/18 职场文书
投标售后服务承诺书
2015/04/29 职场文书
爱国教育主题班会
2015/08/14 职场文书
原生Javascript+HTML5一步步实现拖拽排序
2021/06/12 Javascript
剧场版《转生恶役只好拔除破灭旗标》公开最新视觉图 2023年上映
2022/04/02 日漫