读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 相关文章推荐
符合标准的js表单提交的代码
Sep 13 Javascript
前淘宝前端开发工程师阿当的PPT中有JS技术理念问题
Jan 15 Javascript
使用jQuery.wechat构建微信WEB应用
Oct 09 Javascript
JS如何判断是否为ie浏览器的方法(包括IE10、IE11在内)
Dec 13 Javascript
JavaScript事件代理和委托详解
Apr 08 Javascript
JS结合bootstrap实现基本的增删改查功能
Jul 22 Javascript
AngularJS中的DOM操作用法分析
Nov 04 Javascript
BootStrap 表单控件之单选按钮水平排列
May 23 Javascript
JavaScript创建对象的七种方式全面总结
Aug 21 Javascript
微信小程序实现折叠与展开文章功能
Jun 12 Javascript
JS中验证整数和小数的正则表达式
Oct 08 Javascript
jquery无缝图片轮播组件封装
Nov 25 jQuery
基于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
一个用mysql_odbc和php写的serach数据库程序
2006/10/09 PHP
初次接触php抽象工厂模式(Elgg)
2010/03/21 PHP
PHP调用.NET的WebService 简单实例
2015/03/27 PHP
php去掉文件前几行的方法
2015/07/29 PHP
Laravel Memcached缓存驱动的配置与应用方法分析
2016/10/08 PHP
PHP实现大数(浮点数)取余的方法
2017/02/18 PHP
PHP 信号管理知识整理汇总
2017/02/19 PHP
thinkPHP框架中执行事务的方法示例
2018/05/31 PHP
在模板页面的js使用办法
2010/04/01 Javascript
jquery 之 $().hover(func1, funct2)使用方法
2012/06/14 Javascript
js控制表单不能输入空格的小例子
2013/11/20 Javascript
Javascript验证用户输入URL地址是否为空及格式是否正确
2014/10/09 Javascript
Javascript中arguments对象详解
2014/10/22 Javascript
JS+CSS实现仿新浪微博搜索框的方法
2015/02/24 Javascript
浅谈javascript事件取消和阻止冒泡
2015/05/26 Javascript
AngularJS中的$watch(),$digest()和$apply()区分
2016/04/04 Javascript
AngularJS基础 ng-value 指令简单示例
2016/08/03 Javascript
JS中使用FormData上传文件、图片的方法
2016/08/07 Javascript
Angular4项目中添加i18n国际化插件ngx-translate的步骤详解
2017/07/02 Javascript
JS实现仿微信支付弹窗功能
2018/06/25 Javascript
监听angularJs列表数据是否渲染完毕的方法示例
2018/11/07 Javascript
vue 插件的方法代码详解
2019/06/06 Javascript
Javascript实现简易天数计算器
2020/05/18 Javascript
基于vue 动态菜单 刷新空白问题的解决
2020/08/06 Javascript
在Python中使用CasperJS获取JS渲染生成的HTML内容的教程
2015/04/09 Python
浅析Python中MySQLdb的事务处理功能
2016/09/21 Python
python thrift搭建服务端和客户端测试程序
2018/01/17 Python
jupyter notebook引用from pyecharts.charts import Bar运行报错
2020/04/23 Python
python数字图像处理实现直方图与均衡化
2018/05/04 Python
Python提取支付宝和微信支付二维码的示例代码
2019/02/15 Python
Python Dataframe常见索引方式详解
2020/05/27 Python
python中zip()函数遍历多个列表方法
2021/02/18 Python
什么是静态路由,其特点是什么?什么是动态路由,其特点是什么?
2013/07/26 面试题
分层教学实施方案
2014/03/19 职场文书
司机个人年终总结
2015/03/03 职场文书
圆明园纪录片观后感
2015/06/03 职场文书