读jQuery之十三 添加事件和删除事件的核心方法


Posted in Javascript onAugust 23, 2011

jQuery的事件模块严重依赖于其数据储存(jQuery.data),你会发现我的代码中的dataManager对象对应它。
这里只提供bind和unbind方法。暂不包含
1, 事件命名空间(event namespace)
2, 事件代理(event delegation)
3, 特殊事件如dom ready
接口如下:

E.bind(el, 'click', fn); 
E.bind(el, 'click', fn, data); 
E.unbind(el, 'click', fn); 
E.unbind(el, 'click'); 
E.unbind(el);

/** 
* Event from jQuery 
* 2011-06-20 snandy 
* 
* A number of helper functions used for managing events. 
* Many of the ideas behind this code originated from jQuery library (1.6.2). 
* 
* example 
* 
* E.bind(el, 'click', fn); 
* 
* E.bind(el, 'click', fn, data); 
* 
* E.unbind(el, 'click', fn); 
* 
* E.unbind(el, 'click'); 
* 
* E.unbind(el); 
* 
*/ 
E = function( window ) { 
var uuid = 0, 
globalCache = {}, 
doc = window.document, 
w3c = !!doc.addEventListener, 
expando = 'snandy' + (''+Math.random()).replace(/\D/g, ''), 
addListener = w3c ? 
function(el, type, fn) { el.addEventListener(type, fn, false); } : 
function(el, type, fn) { el.attachEvent('on' + type, fn); }, 
removeListener = w3c ? 
function(el, type, fn) { el.removeEventListener(type, fn, false); } : 
function(el, type, fn) { el.detachEvent('on' + type, fn); }; 
dispatch = w3c ? 
function( el, type ){ 
try{ 
var evt = doc.createEvent('Event'); 
evt.initEvent( type, true, true ); 
el.dispatchEvent( evt ); 
}catch( e ){ alert( e ) }; 
} : 
function( el, type ){ 
try{ 
el.fireEvent( 'on' + type ); 
}catch( e ){ alert( e ); } 
}, 
dataManager = { 
data : function ( elem, name, data ) { 
var getByName = typeof name === "string", 
thisCache, 
isNode = elem.nodeType, 
cache = isNode ? globalCache : elem, 
id = isNode ? elem[ expando ] : elem[ expando ] && expando; 
if(!id && isNode) { 
elem[expando] = id = ++uuid; 
} 
if(!cache[id]){ 
cache[id] = {}; 
} 
thisCache = cache[id]; 
if(data !== undefined) { 
thisCache[name] = data; 
} 
return getByName ? thisCache[name] : thisCache; 
}, 
removeData : function ( elem, name ) { 
var id = elem[expando], 
thisCache = globalCache[id]; 
if(!id || !thisCache){ 
return; 
} 
if(typeof name === 'string') { 
delete thisCache[name]; 
}else{ 
delete globalCache[id]; 
} 
} 
}; 
function returnFalse() { 
return false; 
} 
function returnTrue() { 
return true; 
} 
function now() { 
return (new Date).getTime(); 
} 
function isEmptyObject( obj ){ 
for( var i in obj ){ 
return false; 
} 
return true; 
} 
function addEvent (elem, types, handler, data) { 
if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 
return; 
} 
if ( handler === false ) { 
handler = returnFalse; 
} else if ( !handler ) { 
return; 
} 
var elemData = dataManager.data( elem ), 
events = elemData.events, 
eventHandle = elemData.handle, 
types = types.split(" "); 
if ( !events ) { 
elemData.events = events = {}; 
} 
if ( !eventHandle ) { 
elemData.handle = eventHandle = function ( e ) { 
return evtHandle.call( eventHandle.elem, e ); 
}; 
} 
eventHandle.elem = elem; 
var type, i = 0; 
while ( type = types[i++] ) { 
var handleObj = {handler : handler, data : data}, 
handlers = events[type]; 
if ( !handlers ) { 
handlers = events[type] = []; 
addListener( elem, type, eventHandle ); 
} 
handlers.push( handleObj ); 
} 
elem = null; 
} 
function evtHandle ( event ) { 
event = fixEvent( event || window.event ); 
var handlers = ((dataManager.data(this, "events") || {})[event.type] || []).slice(0); 
event.currentTarget = this; 
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.call( this, event ); 
if( ret !== undefined ) { 
if( ret === false ) { 
event.preventDefault(); 
event.stopPropagation(); 
} 
} 
if( event.isImmediatePropagationStopped() ) { 
break; 
} 
} 
} 
function removeEvent( elem, types, handler ) { 
// don't do events on text and comment nodes 
if( elem.nodeType === 3 || elem.nodeType === 8 ) { 
return; 
} 
if( handler === false ) { 
handler = returnFalse; 
} 
var type, origType, i = 0, j, 
elemData = dataManager.data( elem ), 
events = elemData && elemData.events; 
if( !elemData || !events ) { 
return; 
} 
// Unbind all events for the element 
if( !types ) { 
types = types || ""; 
for ( type in events ) { 
removeEvent( elem, type ); 
} 
return; 
} 
// Handle multiple events separated by a space 
// jQuery(...).unbind("mouseover mouseout", fn); 
types = types.split(" "); 
while( (type = types[ i++ ]) ) { 
origType = type; 
handleObj = null; 
eventType = events[ type ]; 
if( !eventType ) { 
continue; 
} 
if( !handler ) { 
for ( j = 0; j < eventType.length; j++ ) { 
handleObj = eventType[ j ]; 
removeEvent( elem, origType, handleObj.handler ); 
eventType.splice( j--, 1 ); 
} 
continue; 
} 
for( j = 0; j < eventType.length; j++ ) { 
handleObj = eventType[ j ]; 
if( handler === handleObj.handler ) { 
// remove the given handler for the given type 
eventType.splice( j--, 1 ); 
} 
} 
} 
// remove generic event handler if no more handlers exist 
if ( eventType.length === 0 ) { 
delete events[ origType ]; 
} 
// Remove the expando if it's no longer used 
if ( isEmptyObject( events ) ) { 
var handle = elemData.handle; 
if ( handle ) { 
handle.elem = null; 
} 
delete elemData.events; 
delete elemData.handle; 
if ( isEmptyObject( elemData ) ) { 
dataManager.removeData( elem, 'events' ); 
} 
} 
} 
function Event( src ) { 
this.originalEvent = src; 
this.type = src.type; 
this.timeStamp = now(); 
} 
Event.prototype = { 
preventDefault: function() { 
this.isDefaultPrevented = returnTrue; 
var e = this.originalEvent; 
if( e.preventDefault ) { 
e.preventDefault(); 
} 
e.returnValue = false; 
}, 
stopPropagation: function() { 
this.isPropagationStopped = returnTrue; 
var e = this.originalEvent; 
if( e.stopPropagation ) { 
e.stopPropagation(); 
} 
e.cancelBubble = true; 
}, 
stopImmediatePropagation: function() { 
this.isImmediatePropagationStopped = returnTrue; 
this.stopPropagation(); 
}, 
isDefaultPrevented: returnFalse, 
isPropagationStopped: returnFalse, 
isImmediatePropagationStopped: returnFalse 
}; 
function fixEvent( evt ) { 
var props = "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), 
len = props.length; 
var originalEvent = evt; 
evt = new Event(originalEvent); 
for(var i = len, prop; i;) { 
prop = props[ --i ]; 
evt[ prop ] = originalEvent[ prop ]; 
} 
if(!evt.target) { 
evt.target = evt.srcElement || document; 
} 
if( evt.target.nodeType === 3 ) { 
evt.target = evt.target.parentNode; 
} 
if( !evt.relatedTarget && evt.fromElement ) { 
evt.relatedTarget = evt.fromElement === evt.target ? evt.toElement : evt.fromElement; 
} 
if( evt.pageX == null && evt.clientX != null ) { 
var doc = document.documentElement, body = document.body; 
evt.pageX = evt.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); 
evt.pageY = evt.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); 
} 
if( !evt.which && ((evt.charCode || evt.charCode === 0) ? evt.charCode : evt.keyCode) ) { 
evt.which = evt.charCode || evt.keyCode; 
} 
if( !evt.metaKey && evt.ctrlKey ) { 
evt.metaKey = evt.ctrlKey; 
} 
if( !evt.which && evt.button !== undefined ) { 
evt.which = (evt.button & 1 ? 1 : ( evt.button & 2 ? 3 : ( evt.button & 4 ? 2 : 0 ) )); 
} 
return evt; 
} 
function bind ( el, type, fn, data ) { 
var handler; 
if( typeof type === "object" ) { 
for( var key in type ) { 
bind(el, key, type[key], data); 
} 
return; 
} 
handler = fn; 
addEvent( el, type, handler, data ); 
} 
function unbind ( el, type, fn ) { 
if( typeof type === "object" ) { 
for ( var key in type ) { 
unbind( el, key, type[key] ); 
} 
}else { 
removeEvent( el, type, fn ); 
} 
} 
return { 
data : dataManager.data, 
removeData : dataManager.removeData, 
bind : bind, 
unbind : unbind 
}; 
}(this);
Javascript 相关文章推荐
IE 当eval遇上function的处理
Aug 09 Javascript
JavaScript四种调用模式和this示例介绍
Jan 02 Javascript
javascript不同类型数据之间的运算的转换方法
Feb 13 Javascript
React快速入门教程
Jan 17 Javascript
JS实现css hover操作的方法示例
Apr 07 Javascript
基于匀速运动的实例讲解(侧边栏,淡入淡出)
Oct 17 Javascript
AngularJS实现的select二级联动下拉菜单功能示例
Oct 25 Javascript
浅谈vue-cli加载不到dev-server.js的解决办法
Nov 24 Javascript
js实时监控文本框输入字数的实例代码
Jan 18 Javascript
在 vue-cli v3.0 中使用 SCSS/SASS的方法
Jun 14 Javascript
微信小程序-可移动菜单的实现过程详解
Jun 24 Javascript
微信小程序 行的删除和增加操作实现详解
Sep 29 Javascript
基于jquery实现的类似百度搜索的输入框自动完成功能
Aug 23 #Javascript
jquery 回车事件实现代码
Aug 23 #Javascript
基于jquery的大众点评,分类导航实现代码
Aug 23 #Javascript
20个非常棒的 jQuery 幻灯片插件和教程分享
Aug 23 #Javascript
基于jquery实现的鼠标拖拽元素复制并写入效果
Aug 23 #Javascript
一些有用的JavaScript和jQuery的片段分享
Aug 23 #Javascript
Fastest way to build an HTML string(拼装html字符串的最快方法)
Aug 20 #Javascript
You might like
PHP动态输出JavaScript代码实例
2015/02/12 PHP
PHP判断浏览器、判断语言代码分享
2015/03/05 PHP
php实现将字符串按照指定距离进行分割的方法
2015/03/14 PHP
一段效率很高的for循环语句使用方法
2007/08/13 Javascript
JavaScript 设计模式学习 Factory
2009/07/29 Javascript
将CKfinder整合进CKEditor3.0的新方法
2010/01/10 Javascript
Js 代码中,ajax请求地址后加随机数防止浏览器缓存的原因
2013/05/07 Javascript
jquery实现的一个文章自定义分段显示功能
2014/05/23 Javascript
JavaScript处理解析JSON数据过程详解
2015/09/11 Javascript
JS实现网页上随滚动条滚动的层效果代码
2015/11/04 Javascript
JavaScript入门系列之知识点总结
2016/03/24 Javascript
基于jQuery实现多标签页切换的效果(web前端开发)
2016/07/24 Javascript
JSON与XML的区别对比及案例应用
2016/11/11 Javascript
从vue源码看props的用法
2019/01/09 Javascript
微信小程序代码上传、审核发布小程序
2019/05/18 Javascript
JavaScript 生成唯一ID的几种方式
2021/02/19 Javascript
python使用配置文件过程详解
2019/12/28 Python
Python连接HDFS实现文件上传下载及Pandas转换文本文件到CSV操作
2020/06/06 Python
keras导入weights方式
2020/06/12 Python
总结python 三种常见的内存泄漏场景
2020/11/20 Python
css3和jquery实现的可折叠导航菜单适合放在手机网页的导航菜单
2014/09/02 HTML / CSS
Html5让容器充满屏幕高度或自适应剩余高度的布局实现
2020/05/14 HTML / CSS
台湾饭店和机票预订网站:Expedia台湾
2016/08/05 全球购物
Mavi牛仔裤美国官网:土耳其著名牛仔品牌
2016/09/24 全球购物
DOUGLAS荷兰:购买香水和化妆品
2020/10/24 全球购物
说出你对remoting 和webservice的理解和应用
2014/06/08 面试题
事业单位个人应聘自荐信
2013/09/21 职场文书
周年庆典邀请函范文
2014/01/23 职场文书
幼儿园大班教学反思
2014/02/10 职场文书
论文诚信承诺书
2014/05/23 职场文书
小学捐书活动总结
2014/07/05 职场文书
2014机关干部学习“焦裕禄精神”思想汇报
2014/09/19 职场文书
创先争优宣传标语
2014/10/08 职场文书
证婚人婚礼致辞
2015/07/28 职场文书
学生会干部任命书
2015/09/21 职场文书
承诺书应该怎么写?
2019/09/10 职场文书