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模块模式分析
May 16 Javascript
基于jquery.Jcrop的头像编辑器
Mar 01 Javascript
JavaScript高级程序设计 阅读笔记(七) ECMAScript中的语句
Feb 27 Javascript
在JavaScript里嵌入大量字符串常量的实现方法
Jul 07 Javascript
JS小功能(button选择颜色)简单实例
Nov 29 Javascript
js采用map取到id集合组并且实现点击一行选中一行
Dec 16 Javascript
全面解析JavaScript的Backbone.js框架中的Router路由
May 05 Javascript
深入研究jQuery图片懒加载 lazyload.js使用方法
Aug 16 jQuery
Vue.js做select下拉列表的实例(ul-li标签仿select标签)
Mar 02 Javascript
vue 本地环境跨域请求proxyTable的方法
Sep 19 Javascript
Vue 处理表单input单行文本框的实例代码
May 09 Javascript
Bootstrap告警框(alert)实现弹出效果和短暂显示后上浮消失的示例代码
Aug 27 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
允许phpmyadmin空密码登录的配置方法
2011/05/29 PHP
destoon设置自定义搜索的方法
2014/06/21 PHP
php实现建立多层级目录的方法
2014/07/19 PHP
PHP设计模式之迭代器模式
2016/06/17 PHP
Centos 6.5系统下编译安装PHP 7.0.13的方法
2016/12/19 PHP
PHP+fiddler抓包采集微信文章阅读数点赞数的思路详解
2019/12/20 PHP
删除重复数据的算法
2006/11/23 Javascript
JavaScript实现禁止后退的方法
2006/12/27 Javascript
ASP SQL防注入的方法
2008/12/25 Javascript
JavaScript 页面坐标相关知识整理
2010/01/09 Javascript
Extjs gridpanel 出现横向滚动条问题的解决方法
2011/07/04 Javascript
jQuery侧边栏随窗口滚动实现方法
2013/03/04 Javascript
一个JavaScript用逗号分割字符串实例
2014/09/22 Javascript
浅析webapp框架AngularUI的demo
2014/12/21 Javascript
纯js实现无限空间大小的本地存储
2015/06/18 Javascript
jQuery+jsp实现省市县三级联动效果(附源码)
2015/12/03 Javascript
浅谈Javascript中的Label语句
2016/12/14 Javascript
使用vue.js2.0 + ElementUI开发后台管理系统详细教程(一)
2017/01/21 Javascript
jQuery上传插件webupload使用方法
2017/08/01 jQuery
JS随机排序数组实现方法分析
2017/10/11 Javascript
公众号SVG动画交互实战代码
2020/05/31 Javascript
[00:32]10月24、25日 辉夜杯外卡赛附加赛开赛!
2015/10/23 DOTA
python使用PyGame模块播放声音的方法
2015/05/20 Python
Python numpy 点数组去重的实例
2018/04/18 Python
python 实现视频流下载保存MP4的方法
2019/01/09 Python
pyspark给dataframe增加新的一列的实现示例
2020/04/24 Python
matplotlib更改窗口图标的方法示例
2021/02/03 Python
HTML5中图片之间的缝隙完美解决方法
2017/07/07 HTML / CSS
奥巴马演讲稿
2014/01/08 职场文书
《中彩那天》教学反思
2014/02/22 职场文书
历史专业大学生职业生涯规划书
2014/03/13 职场文书
承诺书格式
2014/06/03 职场文书
2014年组织部工作总结
2014/11/14 职场文书
升学宴学生致辞
2015/07/27 职场文书
小学英语新课改心得体会
2016/01/22 职场文书
golang switch语句的灵活写法介绍
2021/05/06 Golang