读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 相关文章推荐
解决 FireFox 下[使用event很麻烦] 的问题.
Aug 22 Javascript
ExtJS中设置下拉列表框不可编辑的方法
May 07 Javascript
Jquery响应回车键直接提交表单操作代码
Jul 25 Javascript
jQuery中prevAll()方法用法实例
Jan 08 Javascript
javascript实现点击提交按钮后显示loading的方法
Jul 03 Javascript
JavaScript保存并运算页面中数字类型变量的写法
Jul 06 Javascript
JavaScript生成SQL查询表单的方法
Aug 13 Javascript
webpack构建换肤功能的思路详解
Nov 27 Javascript
Javascript将图片的绝对路径转换为base64编码的方法
Jan 11 Javascript
React Native 图片查看组件的方法
Mar 01 Javascript
JS实现的视频弹幕效果示例
Aug 17 Javascript
Javascript执行上下文顺序的深入讲解
Nov 04 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的array_diff()函数在处理大数组时的效率问题
2011/11/27 PHP
一个简单的php加密解密函数(动态加密)
2013/06/19 PHP
解析yii数据库的增删查改
2013/06/20 PHP
smarty缓存用法分析
2014/12/16 PHP
PHP时间类完整实例(非常实用)
2015/12/25 PHP
js中对函数设置默认参数值的3种方法
2015/10/23 Javascript
javascript实现简单加载随机色方块
2015/12/25 Javascript
Bootstrap中datetimepicker使用小结
2016/12/28 Javascript
从零开始做一个pagination分页组件
2017/03/15 Javascript
ES6/JavaScript使用技巧分享
2017/12/14 Javascript
Vue列表渲染的示例代码
2018/11/01 Javascript
electron制作仿制qq聊天界面的示例代码
2018/11/26 Javascript
详解vantUI框架在vue项目中的应用踩坑
2018/12/06 Javascript
layer 关闭指定弹出层的例子
2019/09/25 Javascript
js实现整体缩放页面适配移动端
2020/03/31 Javascript
JS可断点续传文件上传实现代码解析
2020/07/30 Javascript
[48:44]2014 DOTA2国际邀请赛中国区预选赛5.21 TongFu VS HGT
2014/05/22 DOTA
[41:12]Liquid vs Secret 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.24
2019/09/10 DOTA
Python中如何优雅的合并两个字典(dict)方法示例
2017/08/09 Python
Python从零开始创建区块链
2018/03/06 Python
Python图像的增强处理操作示例【基于ImageEnhance类】
2019/01/03 Python
深入理解Django-Signals信号量
2019/02/19 Python
使用Python实现文字转语音并生成wav文件的例子
2019/08/08 Python
python中利用numpy.array()实现俩个数值列表的对应相加方法
2019/08/26 Python
python并发爬虫实用工具tomorrow实用解析
2019/09/25 Python
Python matplotlib画图时图例说明(legend)放到图像外侧详解
2020/05/16 Python
python两个list[]相加的实现方法
2020/09/23 Python
使用AJAX和Django获取数据的方法实例
2020/10/25 Python
HTML5 Web缓存和运用程序缓存(cookie,session)
2018/01/11 HTML / CSS
西班牙在线宠物商店:zooplus.es
2017/02/24 全球购物
俄罗斯运动鞋商店:Sneakerhead
2018/05/10 全球购物
食品科学与工程专业毕业生求职信范文
2014/07/21 职场文书
大学军训的体会
2014/11/08 职场文书
营销计划书范文
2015/01/17 职场文书
巴黎圣母院观后感
2015/06/10 职场文书
党性教育心得体会(共6篇)
2016/01/21 职场文书