读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 在firebug调试时用console.log的方法
May 10 Javascript
javascript 上下banner替换具体实现
Nov 14 Javascript
JavaScript判断数组是否包含指定元素的方法
Jul 01 Javascript
纯javascript代码实现计算器功能(三种方法)
Sep 07 Javascript
实例讲解避免javascript冲突的方法
Jan 03 Javascript
js 客户端打印html 并且去掉页眉、页脚的实例
Nov 03 Javascript
Angular HMR(热模块替换)功能实现方法
Apr 04 Javascript
vue实现打印功能的两种方法
Sep 07 Javascript
JavaScript实现省市区三级联动
Feb 13 Javascript
微信小程序自定义纯净模态框(弹出框)的实例代码
Mar 09 Javascript
微信小程序实现modal弹出框遮罩层组件(可带文本框)
Dec 20 Javascript
微信小程序实现购物车小功能
Dec 30 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
咖啡语言
2021/03/03 咖啡文化
PHP通用检测函数集合
2006/11/25 PHP
PHP 之 写时复制介绍(Copy On Write)
2014/05/13 PHP
Yii2框架制作RESTful风格的API快速入门教程
2016/11/08 PHP
深入浅出讲解:php的socket通信原理
2016/12/03 PHP
Swoole源码中如何查询Websocket的连接问题详解
2020/08/30 PHP
jquery 简单应用示例总结
2013/08/09 Javascript
js中window.open()的所有参数详细解析
2014/01/09 Javascript
js弹出确认是否删除对话框
2014/03/27 Javascript
Javascript设计模式理论与编程实战之简单工厂模式
2015/11/03 Javascript
javascript html5移动端轻松实现文件上传
2020/03/27 Javascript
jQuery实现选项联动轮播效果【附实例】
2016/04/19 Javascript
使用AJAX实现Web页面进度条的实例分享
2016/05/06 Javascript
基于Layer+jQuery的自定义弹框
2020/05/26 Javascript
浅谈js键盘事件全面控制
2016/12/01 Javascript
详解Vue.js基于$.ajax获取数据并与组件的data绑定
2017/05/26 Javascript
vue引入新版 vue-awesome-swiper插件填坑问题
2018/01/25 Javascript
微信小程序实现城市列表选择
2018/06/05 Javascript
JS对象与json字符串相互转换实现方法示例
2018/06/14 Javascript
浅谈vux之x-input使用以及源码解读
2018/11/04 Javascript
使用pm2自动化部署node项目的方法步骤
2019/01/28 Javascript
[02:34]2016完美“圣”典风云人物:BurNIng专访
2016/12/10 DOTA
Python实现快速排序和插入排序算法及自定义排序的示例
2016/02/16 Python
Python进阶:生成器 懒人版本的迭代器详解
2019/06/29 Python
Python叠加两幅栅格图像的实现方法
2019/07/05 Python
Python笔记之观察者模式
2019/11/20 Python
python中Lambda表达式详解
2019/11/20 Python
tensorflow的计算图总结
2020/01/12 Python
python GUI库图形界面开发之PyQt5下拉列表框控件QComboBox详细使用方法与实例
2020/02/27 Python
摩托车和ATV零件、配件和服装的首选在线零售商:MotoSport
2017/12/22 全球购物
意大利高端时尚买手店:Stefania Mode
2018/03/01 全球购物
介绍下Java中==和equals的区别
2013/09/01 面试题
酒店总经理助理职责
2014/02/12 职场文书
采购助理岗位职责
2014/02/16 职场文书
小学毕业感言500字
2014/02/28 职场文书
数学高效课堂实施方案
2014/03/29 职场文书