读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 相关文章推荐
javascript 折半查找字符在数组中的位置(有序列表)
Dec 09 Javascript
深入浅出理解javaScript原型链
May 09 Javascript
基于JS2Image实现圣诞树代码
Dec 24 Javascript
Node.js的MongoDB驱动Mongoose基本使用教程
Mar 01 Javascript
带有定位当前位置的百度地图前端web api实例代码
Jun 21 Javascript
jQuery实现的分页功能示例
Jan 22 Javascript
微信小程序中子页面向父页面传值实例详解
Mar 20 Javascript
微信小程序新增的拖动组件movable-view使用教程
May 20 Javascript
jQuery动态添加元素无法触发绑定事件的解决方法分析
Jan 02 jQuery
JS原生带缩略图的图片切换效果
Oct 10 Javascript
JavaScript 中判断变量是否为数字的示例代码
Oct 22 Javascript
vue实现动态给id赋值,点击事件获取当前点击的元素的id操作
Nov 09 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
mysq GBKl乱码
2006/11/28 PHP
php模拟js函数unescape的函数代码
2012/10/20 PHP
Mysql中分页查询的两个解决方法比较
2013/05/02 PHP
ThinkPHP连接数据库及主从数据库的设置教程
2014/08/22 PHP
php对关联数组循环遍历的实现方法
2015/03/13 PHP
thinkphp3.x中变量的获取和过滤方法详解
2016/05/20 PHP
Yii2.0 Basic代码中路由链接被转义的处理方法
2016/09/21 PHP
关于PHP内置的字符串处理函数详解
2017/02/04 PHP
关于PHP求解三数之和问题详析
2020/11/09 PHP
aspx中利用js实现确认删除代码
2010/07/22 Javascript
javascript跨浏览器的属性判断方法
2014/03/16 Javascript
javasctipt如何显示几分钟前、几天前等
2014/04/30 Javascript
javascript jquery对form元素的常见操作详解
2016/06/12 Javascript
javascript 网页进度条简单实例
2017/02/22 Javascript
vue的安装及element组件的安装方法
2018/03/09 Javascript
通过js示例讲解时间复杂度与空间复杂度
2019/08/06 Javascript
基于JavaScript获取base64图片大小
2019/10/18 Javascript
JS如何实现手机端输入验证码效果
2020/05/13 Javascript
python list排序的两种方法及实例讲解
2017/03/20 Python
django启动uwsgi报错的解决方法
2018/04/08 Python
Flask web开发处理POST请求实现(登录案例)
2018/07/26 Python
解决python给列表里添加字典时被最后一个覆盖的问题
2019/01/21 Python
python实现批量修改服务器密码的方法
2019/08/13 Python
python对Excel的读取的示例代码
2020/02/14 Python
python入门之井字棋小游戏
2020/03/05 Python
Django中FilePathField字段的用法
2020/05/21 Python
python 浮点数四舍五入需要注意的地方
2020/08/18 Python
CSS3与动画有关的属性transition、animation、transform对比(史上最全版)
2017/08/18 HTML / CSS
canvas实现俄罗斯方块的方法示例
2018/12/13 HTML / CSS
Nike挪威官网:Nike.com (NO)
2018/11/26 全球购物
英国打印机墨盒销售网站:Ink Factory
2019/10/07 全球购物
几道数据库的概念性面试题
2014/05/30 面试题
物业管理个人自我评价
2013/11/08 职场文书
党员教师四风自我剖析材料
2014/09/30 职场文书
护理见习报告范文
2014/11/03 职场文书
感谢师恩主题班会
2015/08/17 职场文书