Javascript处理DOM元素事件实现代码


Posted in Javascript onMay 23, 2012

DOM元素都有一些标准事件,一般使用时只要使用onclick=function的方式就可以了,但是当需要为DOM元素添加多个事件,删除事件,或在用Javascript封装控件的时候,为封装的控件添加自定义事件的时候,onclick=function的方式就不够用了,但是浏览器有addEventListener和attachEvent方法可供调用,从而模拟出类似于C#中的事件委托的事件触发机制!

/* 
* 功能:事件处理 
* Author:LQB 
* 时间:2009-1-4 
* #include JCore.js 
*/ 
var JEvents = function(){ 
this.events={}; 
this.addEvent = function(o){//添加事件 
if(typeof o == 'string'){/*strArg1,strArg2……的方式传递参数*/ 
for(var i = 0, a = arguments, v; v = a[i]; i++){ 
v = v.toString().toLowerCase(); 
var enFX = v.indexOf("on")==0 ? v.substr(2) : v; 
if(!this.events[enFX]){ 
this.events[enFX] = true; 
} 
} 
}else{ 
JCore.apply(this.events, o,false); 
} 
}; 
this.addListener = function(eventName,fn,scope/*,Args……*/){//为事件添加处理方法 
if(typeof(eventName)!="string"|| eventName.lenght==0)return; 
if(typeof(fn)!="function")return; 
eventName = eventName.toString().toLowerCase(); 
var enFX = eventName.indexOf("on")==0 ? eventName.substr(2) : eventName; 
if(!this.events[enFX]){ 
throw "Error! Event /"" + eName + "/" doesnt exist." 
} 
var sp = scope||window; 
var callArgs = Array.prototype.slice.call(arguments, 3);//从第4个参数开始 
callArgs = typeof(callArgs)!="undefined"?callArgs:[]; 
var delegate = fn.createDelegate(callArgs,sp);//JCore支持 
//为fn方法创建标记,在删除事件时使用 
if(!fn.uid) { 
var time = new Date(); 
fn.uid= ""+time.getMinutes()+time.getSeconds()+time.getMilliseconds(); 
} 
//标记委托,在删除事件绑定时使用 
delegate.uid = getCacheAttName(enFX,fn.uid); 
if(typeof(this.events[enFX])!="object") 
this.events[enFX]=[]; 
this.events[enFX].push(delegate);//把方法添加到事件列表中 
}; 
this.removeListener = function(eventName,fn){//移除事件绑定 
if(eventName && fn){ 
eventName = eventName.toString().toLowerCase(); 
var enFX = eventName.indexOf("on")==0?eventName.substr(2):eventName; 
var AttName = getCacheAttName(enFX,fn.uid); 
if(typeof(this.events[enFX])=="object"){//存在这个事件 
var functions = this.events[enFX]; 
for(i=0;i<functions.length;i++){//依次查找每个方法 
if(functions[i].uid===AttName){//找到,删除 
this.events[enFX].remove(functions[i]); 
break; 
} 
} 
} 
} 
} 
this.fireEvent = function(eName,eventArg){//触发事件 
eName = eName.toString().toLowerCase(); 
var enFX = eName.indexOf("on")==0 ? eName.substr(2) : eName; 
var Arg = new Array(); 
if(typeof(eventArg)!="undefined"){ 
if(typeof(eventArg)=="array") Arg=eventArg; 
else Arg.push(eventArg); 
} 
if(typeof(this.events[enFX])=="object"){//存在此事件,同时添加了事件处理方法 
var functions = this.events[enFX]; 
for(i=0;i<functions.length;i++){//依次触发所有方法 
functions[i].apply(window,Arg); 
} 
} 
} 
/*---------------------------------------私有方法--------------------------------------*/ 
var getCacheAttName = function(eventName,fnuid){ 
return "handle-"+eventName+"-"+fnuid; 
} 
} 
/*------------------------------------------------------以下是静态方法,用于处理DOM element的事件-----------------------------------------*/ 
var JEventsExtendMethod = { 
cache : {//时间处理缓存,用于标记各个事件处理方法,在删除事件时使用 
eventCache : {}, 
setCache : function(el,Name,value){ 
if(typeof(this.eventCache[el])!="object"){ 
this.eventCache[el]={length :1}; 
} 
this.eventCache[el][Name]=value; 
this.eventCache[el].length++; 
}, 
getCache : function(el,Name){ 
if(typeof(this.eventCache[el]) =="object") 
return this.eventCache[el][Name]; 
else 
return null; 
}, 
removeCache : function(el,Name){ 
if(typeof(this.eventCache[el]) =="object"){ 
delete this.eventCache[el][Name];//删除属性 
this.eventCache[el].length--; 
} 
if(this.eventCache[el] && this.eventCache[el].length ==1)//清除 
delete this.eventCache[el]; 
} 
}, 
getCacheAttName : function(eventName,fnuid){ 
return "handle-"+eventName+"-"+fnuid; 
}, 
bind : function(el,eventName,fn,scope/*,Args……*/){//为elment添加事件处理方法 
if(typeof(el)=="undefined"||el==null)return; 
if(typeof(eventName)!="string"|| eventName.lenght==0)return; 
if(typeof(fn)!="function")return; 
var indexOfon = eventName.toString().toLowerCase().indexOf("on"); 
var enIE = indexOfon==0?eventName:"on"+eventName; 
var enFX = indexOfon==0?eventName.substr(2):eventName; 
var sp = scope||window; 
var callArgs = Array.prototype.slice.call(arguments, 4);//从第5个参数开始 
callArgs = typeof(callArgs)!="undefined"?callArgs:[]; 
var delegate = fn.createDelegate(callArgs,sp);//JCore支持 
if (el.addEventListener){//Mozilla系列,按队列顺序执行 
el.addEventListener(enFX, delegate, false);//第三个参数与触发方式相关 
} else if (el.attachEvent){//非Mozilla系列,按堆栈顺序执行(后加的事件先执行) 
el.attachEvent(enIE, delegate); 
} 
//为fn方法创建标记,在删除事件时使用 
if(!fn.uid) { 
var time = new Date(); 
fn.uid= ""+time.getMinutes()+time.getSeconds()+time.getMilliseconds(); 
} 
if(!el.id){ 
el.id = JCore.id(el,null); 
} 
//标记委托,在删除事件绑定时使用 
var AttName = this.getCacheAttName(enFX,fn.uid); 
this.cache.setCache(el.id,AttName,delegate); 
}, 
unbind : function(el,eventName,fn){//为elment解除事件绑定 
if(typeof(el)=="undefined"||el==null)return; 
var indexOfon = eventName.toString().toLowerCase().indexOf("on"); 
var enIE = indexOfon==0?eventName:"on"+eventName; 
var enFX = indexOfon==0?eventName.substr(2):eventName; 
var AttName = this.getCacheAttName(enFX,fn.uid); 
var delegate = this.cache.getCache(el.id,AttName); 
if(delegate){ 
if (el.removeEventListener){//Mozilla系列 
el.removeEventListener(enFX, delegate, false); 
} else if (el.detachEvent){//非Mozilla系列 
el.detachEvent(enIE, delegate); 
} 
} 
//删除事件缓存 
this.cache.removeCache(el.id,AttName); 
} 
} 
JCore.apply(JEvents,JEventsExtendMethod); 
/*--------------------------------对event的参数包装---------------------------------*/ 
var JEventWrap = function(event){ 
this.xtype="EventWrap"; 
this.data=null; 
this.srcElement = null; //发生事件的文档元素 
this.button = null; //[FX:0-左键,1-中间键,2-右键][IE:1-左键,2-右键,4-中键](仅对onmousedown, onmouseup,onmousemove有效) 
this.type = null; 
this.clientX = 0; //鼠标指针相对客户区或浏览器窗口的X坐标(标准属性) 
this.clientY = 0; //鼠标指针相对客户区或浏览器窗口的Y坐标(标准属性) 
this.offsetX = 0; //鼠标指针相对于源元素的X坐标(兼容属性)(IE) 
this.offsetY = 0; //鼠标指针相对于源元素的Y坐标(兼容属性)(IE) 
this.screenX = 0; //鼠标指针相对于用户显示器的左上角X坐标(兼容属性)(FX) 
this.screenY = 0; //鼠标指针相对于用户显示器的左上角Y坐标(兼容属性)(FX) 
this.altKey = false; //是否Alt键 
this.ctrlKey = false; //是否Ctrl键, 
this.shitfKey = false; //是否Shift键 
this.keyCode = 0; 
this.originaEvent = null; //未包装的原始事件对象 
/*----构造-----*/ 
if(event){ 
if(event.srcElement){//IE 
this.srcElement = event.srcElement; 
this.offsetX = event.offsetX; 
this.offsetY = event.offsetY; 
this.button = event.button; 
} 
else{ 
this.srcElement = event.target; 
this.offsetX = event.clientX - event.target.offsetLeft; 
this.offsetY = event.clientY - event.target.offsetTop; 
} 
this.type = event.type; 
this.altKey = event.altKey; 
this.ctrlKey = event.ctrlKey; 
this.shitfKey = event.shitfKey; 
this.clientX = event.clientX; 
this.clientY = event.clientY; 
this.screenX = event.screenX; 
this.screenY = event.screenY; 
this.keyCode = event.keyCode; 
this.originaEvent = event; 
} 
}

其中JCore.js文件见上一篇日志:面向对象Javascript核心支持代码
Javascript 相关文章推荐
Jquery实现视频播放页面的关灯开灯效果
May 27 Javascript
MVC Ajax Helper或Jquery异步加载部分视图
Nov 29 Javascript
浅谈angularjs依赖服务注入写法的注意点
Apr 24 Javascript
angular之ng-template模板加载
Nov 09 Javascript
js实现鼠标单击Tab表单切换效果
May 16 Javascript
Node 搭建一个静态资源服务器的实现
May 20 Javascript
layui中的switch开关实现方法
Sep 03 Javascript
vue 验证码界面实现点击后标灰并设置div按钮不可点击状态
Oct 28 Javascript
Vue动态加载图片在跨域时无法显示的问题及解决方法
Mar 10 Javascript
JavaScript实现字符串与HTML格式相互转换
Mar 17 Javascript
JS中FileReader类实现文件上传及时预览功能
Mar 27 Javascript
JavaScript如何实现图片处理与合成
May 29 Javascript
面向对象Javascript核心支持代码分享
May 23 #Javascript
Package.js  现代化的JavaScript项目make工具
May 23 #Javascript
检测input每次的输入是否合法遇到汉字输入就有问题
May 23 #Javascript
JavaScript可否多线程? 深入理解JavaScript定时机制
May 23 #Javascript
setTimeout的延时为0时多个浏览器的区别
May 23 #Javascript
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
May 23 #Javascript
jQuery 瀑布流 浮动布局(一)(延迟AJAX加载图片)
May 23 #Javascript
You might like
PHP查看当前变量类型的方法
2015/07/31 PHP
PHP多维数组转一维数组的简单实现方法
2015/12/23 PHP
orm获取关联表里的属性值
2016/04/17 PHP
Thinkphp3.2简单解决多文件上传只上传一张的问题
2017/09/26 PHP
JS幻灯片可循环播放可平滑旋转带滚动导航(自写)
2013/08/05 Javascript
jQuery学习笔记之 Ajax操作篇(一) - 数据加载
2014/06/23 Javascript
js实现键盘操作实现div的移动或改变的原理及代码
2014/06/23 Javascript
用js传递value默认值的示例代码
2014/09/11 Javascript
jQuery对于显示和隐藏等常用状态的判断方法
2014/12/13 Javascript
js获取form的方法
2015/05/06 Javascript
JavaScript基本数据类型及值类型和引用类型
2015/08/25 Javascript
基于Flowplayer打造一款免费的WEB视频播放器附源码
2015/09/06 Javascript
BootStrap的alert提示框的关闭后再显示怎么解决
2016/05/17 Javascript
JS用斜率判断鼠标进入DIV四个方向的方法
2016/11/07 Javascript
JS填写银行卡号每隔4位数字加一个空格
2016/12/19 Javascript
网页中右键功能的实现方法之contextMenu的使用
2017/02/20 Javascript
Angular 2.0+ 的数据绑定的实现示例
2017/08/09 Javascript
three.js 入门案例详解
2018/01/23 Javascript
详解Node.js中path模块的resolve()和join()方法的区别
2018/10/29 Javascript
小程序实现左滑删除效果
2019/07/25 Javascript
详解package.json版本号规则
2019/08/01 Javascript
Node.js API详解之 util模块用法实例分析
2020/05/09 Javascript
微信小程序完美解决scroll-view高度自适应问题的方法
2020/08/08 Javascript
vue 如何使用递归组件
2020/10/23 Javascript
详解Python的Django框架中的模版相关知识
2015/07/15 Python
Python中用post、get方式提交数据的方法示例
2017/09/22 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
2019/10/16 Python
通俗易懂了解Python装饰器原理
2020/09/17 Python
伦敦一卡通:The London Pass
2018/11/30 全球购物
eBay英国购物网站:eBay.co.uk
2019/06/19 全球购物
什么情况下你必须要把一个类定义为abstract的
2013/01/06 面试题
医学生职业规划范文
2014/01/05 职场文书
初中差生评语
2014/12/29 职场文书
长江三峡导游词
2015/01/31 职场文书
党支部考察意见范文
2015/06/02 职场文书
祝福语集锦:给满月宝宝的祝福语
2019/11/20 职场文书