理解JavaScript中的事件


Posted in Javascript onSeptember 23, 2006

在很多语言的学习中,“事件”都是一个比较难理解,但是又是一个很重要的概念。javascript中的事件处理也是一样,正因为有了事件处理,才会出现Ajax拖动的效果。本文就讨论一下JavaScript中的事件处理,读过之后,您就会知道,很多Ajax框架实现拖动效果的原理了。
一、 IE Event对象
(一)IE Event对象的主要属性和方法

在IE中有一个专门负责事件处理的对象Event,这个对象负责对事件的处理,含有很多的属性和方法,通过这些方法和属性的调用,就能完成很多的事件处理。

type:事件的类型,就是HTML标签属性中,没有“on”前缀之后的字符串,例如“Click”就代表单击事件。

srcElement:事件源,就是发生事件的元素。

button:声明了被按下的鼠标键,是一个整数。1代表鼠标左键,2代表鼠标右键,4代表鼠标的中间键,如果按下了多个鼠标键,就把这些值加在一起,所以3就代表左右键同时按下。

clientX/clientY:是指事件发生的时候,鼠标的横、纵坐标,返回的是整数,它们的值是相对于包容窗口的左上角生成的。

offsetX/offsetY:鼠标指针相对于源元素的位置,可以确定单击Image对象的哪个象素。

altKey,ctrlKey,shiftKey:顾名思义,这些属性是指鼠标事件发生的时候,是否同时按住了Alt、Ctrl或者Shift键,返回的是一个布尔值。

keyCode:返回keydown和keyup事件发生的时候,按键的代码以及keypress事件的Unicode字符。

fromElement、toElement前者是指代mouseover事件移动过的文档元素,后者指代mouseout事件中鼠标移动到的文档元素。

cancelBubble:一个布尔属性,把它设置为true的时候,将停止事件进一步起泡到包容层次的元素。

returnValue:一个布尔值属性,设置为false的时候可以组织浏览器执行默认的事件动作,相当于<a href=”#” onclick=”ProcessMethod();return false;” />。

attachEvent()和detachEvent()方法:为制定DOM对象事件类型注册多个事件处理函数的方法,它们有两个参数,第一个是事件类型,第二个是事件处理函数。在attachEvent()事件执行的时候,this关键字指向的是window对象,而不是发生事件的那个元素。

(二)IE Event对象的一些说明

1.IE Event对象是一个全局属性

在IE中,不能把Event对象作为参数传递给事件处理程序,只能用window.event或者event来引用Event对象。因为在IE中,Event是window的一个属性,也就是说event是一个全局变量,这个变量提供了事件的细节。

2.IE中事件的起泡:IE中事件可以沿着包容层次一点点起泡到上层,也就是说,下层的DOM节点定义的事件处理函数,到了上层的节点如果还有和下层相同事件类型的事件处理函数,那么上层的事件处理函数也会执行。例如,<div>标签包含了<a>,如果这两个标签都有 onclick事件的处理函数,那么执行的情况就是先执行<a>标签的onclick事件处理函数,再执行<div>的事件处理函数。如果希望<a>的事件处理函数执行完毕之后,不希望执行上层的<div>的onclick的事件处理函数了,那么就把 cancelBubble设置为false即可。


二、 IE中拖动DOM元素的例子

/* 
  该函数由mousedown事件处理调用 
  它为随后发生的mousemove和mouseup事件注册了临时的捕捉事件处理程序 
  并用这些事件处理程序拖动指定的文档元素 
  第二个参数必须是mousedown事件的事件对象 
*/ 
function beginDrag(elementToDrag,event) 
{ 
  //该元素当前位于何处 
  //该元素的样式性质必须具有left和top CSS属性 
  //此外,我们假定他们用象素做单位 
  //var x=parseInt(elementToDrag.style.left); 
  //var y=parseInt(elementToDrag.style.top);   //计算一个点和鼠标点击之间的距离,下面的嵌套的moveHandler函数需要这些值 
  var deltaX=event.clientX-parseInt(elementToDrag.style.left); 
  var deltaY=event.clientY-parseInt(elementToDrag.style.top); 
//  注册mousedown事件后发生的mousemove和mouseup事件的处理程序 
//  注意,它们被注册为文档的捕捉事件处理程序 
//  在鼠标按钮保持按下的状态的时候,这些事件处理程序保持活动的状态 
//  在按钮被释放的时候,它们被删除 
  document.attachEvent("onmousemove",moveHandler); 
  document.attachEvent("onmouseup",upHandler); 
  //我们已经处理了该事件,不要让别的元素看到它 
 event.cancelBubble=true; 
 event.returnValue=false; 
  /* 
    这是在元素被拖动时候捕捉mousemove事件的处理程序,它响应移动的元素 
  */ 
  function moveHandler(e)  
  { 
    //把元素移动到当前的鼠标位置 
    e=window.event; 
    elementToDrag.style.left=(event.clientX-deltaX)+"px"; 
    elementToDrag.style.top=(event.clientY-deltaY)+"px"; 
    //不要让别的元素看到该事件 
    event.cancelBubble=true;    
  } 
  /* 
    该事件将捕捉拖动结束的时候发生的mouseup事件 
  */ 
  function upHandler(e) 
  { 
    //注销事件处理程序 
      document.detachEvent("onmouseup",upHandler); 
      document.detachEvent("onmousemove",moveHandler);} 
      event.cancelBubble=true; 
    }  
   调用它的HTML文件代码: 
 <html> 
 <head> 
     <title>Untitled Page</title> 
     <script type="text/javascript" src="dragIE.js"></script> 
 </head> 
 <body> 
 <div style="position:absolute;left:100px;top:100px;background-color:White;border:solid black;"> 
   <div style="background-color:Gray;border-bottom:solid black;padding:3px;font-family:Sans-Serif;font-weight:bold;" onmousedown="beginDrag(this.parentNode,event);"> 
   拖动我          
   </div> 
   <div> 
   <p>This is a test.Testing,testing</p></div> 
 </div> 
 </body>

三、 DOM中的高级事件处理
 IE 6中的事件处理,并不是W3C DOM标准的事件处理模型,所以如果上述代码运行在Mozilla Firefox的浏览器中,就会失去作用,同时即将发布的IE 7也将支持W3C DOM的二级标准,所以掌握DOM的高级事件处理显得就很重要了,因为W3C DOM二级标准是未来Web的发展方向,同时W3C DOM的API非常常用,为未来更加复杂的Web开发提供了良好的基础。
(一)事件处理程序的作用域和事件的传播

在正式讨论DOM高级事件处理之前,我们有必要了解一下事件处理程序的作用域。事件处理程序的作用域要比普通的函数作用域复杂很多。普通的函数作用域链比较容易,例如在一个普通函数中查找一个变量a,那么JavaScript解释器会先在该函数的调用对象中查找是否有a这个变量,如果没有,将会在作用域链的下一个对象,一般是全局对象中查找。但是事件处理程序没这么简单,特别是用HTML的属性定义的,它们的作用域链的头部是调用它们的对象,而下一个对象并不是全局对象,而是触发事件处理程序的对象。这样就会出现一个问题,window和document都有一个方法open(),如果open()前面不加修饰,那么在事件处理的函数中将会调用document.open()方法,而不是常用的window.open()方法,所以使用的时候应该明确指明是 window.open()。
(二)事件传播和注册事件处理程序
1.事件传播

在二级DOM标准中,事件处理程序比较复杂,当事件发生的时候,目标节点的事件处理程序就会被触发执行,但是目标节点的父节点也有机会来处理这个事件。事件的传播分为三个阶段,首先是捕捉阶段,事件从 Document对象沿着DOM树向下传播到目标节点,如果目标的任何一个父节点注册了捕捉事件的处理程序,那么事件在传播的过程中就会首先运行这个程序。下一个阶段就是发生在目标节点自身了,注册在目标节点上的相应的事件处理程序就会执行;最后是起泡阶段,事件将从目标节点向上传回给父节点,同样,如果父节点有相应的事件处理程序也会处理。在IE中,没有捕捉的阶段,但是有起泡的阶段。可以用stopPropagating()方法来停止事件传播,也就是让其他元素对这个事件不可见,在IE 6中,就是把cancelBubble设置为true。
2.注册事件处理程序

和IE一样, DOM标准也有自己的事件处理程序,不过DOM二级标准的事件处理程序比IE的强大一些,事件处理程序的注册用addEventListner方法,该方法有三个参数,第一个是事件类型,第二个是处理的函数,第三个是一个布尔值,true表示制定的事件处理程序将在事件传播的阶段用于捕捉事件,否则就不捕捉,当事件发生在对象上才触发执行这个事件处理的函数,或者发生在该对象的字节点上,并且向上起泡到这个对象上的时候,触发执行这个事件处理的函数。例如:document.addEventListener("mousemove",moveHandler,true);就是在mousemove事件发生的时候,调用moveHandler函数,并且可以捕捉事件。

可以用addEventListener为一个事件注册多个事件处理的程序,但是这些函数的执行顺序是不确定,并不像C#那样按照注册的顺序执行。

在Mozilla Firefox中用addEventListener注册一个事件处理程序的时候,this关键字就表示调用事件处理程序的文档元素,但是其他浏览器并不一定是这样,因为这不是DOM标准,正确的做法是用currentTarget属性来引用调用事件处理程序的文档元素。
3.二级DOM标准中的Event

和IE不同的是,W3C DOM中的Event对象并不是window全局对象下面的属性,换句话说,event不是全局变量。通常在DOM二级标准中,event作为发生事件的文档对象的属性。Event含有两个子接口,分别是UIEvent和MutationEvent,这两个子接口实现了Event的所有方法和属性,而 MouseEvent接口又是UIEvent的子接口,所以实现了UIEvent和Event的所有方法和属性。下面,我们就看看Event、 UIEvent和MouseEvent的主要属性和方法。

1.Event

  type:事件类型,和IE类似,但是没有“on”前缀,例如单击事件只是“click”。

  target:发生事件的节点。

  currentTarget:发生当前正在处理的事件的节点,可能是Target属性所指向的节点,也可能由于捕捉或者起泡,指向Target所指节点的父节点。

  eventPhase:指定了事件传播的阶段。是一个数字。

  timeStamp:事件发生的时间。

  bubbles:指明该事件是否起泡。

  cancelable:指明该事件是否可以用preventDefault()方法来取消默认的动作。

  preventDefault()方法:取消事件的默认动作;

  stopPropagation()方法:停止事件传播。

2.UIEvent

  view:发生事件的window对象。

  detail:提供事件的额外信息,对于单击事件、mousedown和mouseup事件都代表的是点击次数。

3.MouseEvent

 button:一个数字,指明在mousedown、mouseup和单击事件中,鼠标键的状态,和IE中的button属性类似,但是数字代表的意义不一样,0代表左键,1代表中间键,2代表右键。

 altKey、ctrlKey、shiftKey、metaKey:和IE相同,但是IE没有最后一个。

 clientX、clientY:和IE的含义相同,但是在DOM标准中,这两个属性值都不考虑文档的滚动情况,也就是说,无论文档滚动到哪里,只要事件发生在窗口左上角,clientX和clientY都是0,所以在IE中,要想得到事件发生的坐标相对于文档开头的位置,要加上 document.body.scrollLeft和document.body.scrollTop。

 screenX、screenY:鼠标指针相对于显示器左上角的位置,如果你想打开新的窗口,这两个属性很重要。

 relatedTarget:和IE中的fromElement、toElement类似,除了对于mouseover和mouseout有意义外,其他的事件没什么意义。
(三)兼容于两种主流浏览器的拖动DOM元素的例子

好了,刚才讲了这么多DOM编程和IE中的事件,那么如何编写兼容IE和Mozilla Firefox两种主流浏览器的拖拽程序呢?代码如下:

function beginDrag(elementToDrag,event) 
{ 
  var deltaX=event.clientX-parseInt(elementToDrag.style.left); 
  var deltaY=event.clientY-parseInt(elementToDrag.style.top); if(document.addEventListener) 
{ 
  document.addEventListener("mousemove",moveHandler,true); 
  document.addEventListener("mouseup",upHandler,true); 
} 
else if(document.attachEvent) 
{ 
  document.attachEvent("onmousemove",moveHandler); 
  document.attachEvent("onmouseup",upHandler); 
} 
  if(event.stopPropagation)   event.stopPropagation(); 
  else event.cancelBubble=true; 
  if(event.preventDefault)  event.preventDefault(); 
  else event.returnValue=false; 
  function moveHandler(e)  
  { 

if (!e) e=window.event; //如果是IE的事件对象,那么就用window.event 

//全局属性,否则就用DOM二级标准的Event对象。 
    elementToDrag.style.left=(event.clientX-deltaX)+"px"; 
    elementToDrag.style.top=(event.clientY-deltaY)+"px"; 
     if(event.stopPropagation)   event.stopPropagation(); 
    else event.cancelBubble=true; 
  } 
  function upHandler(e) 
  { 
       if(document.removeEventListener) 
    { 
      document.removeEventListener("mouseup",upHandler,true); 
      document.removeEventListener("mousemove",moveHandler,true);} 
      else 
    { 
      document.detachEvent("onmouseup",upHandler); 
      document.detachEvent("onmousemove",moveHandler);} 
    } 
      if(event.stopPropagation)   event.stopPropagation(); 
    else event.cancelBubble=true;     
  } 
Javascript 相关文章推荐
$.get获取一个文件的内容示例代码
Sep 11 Javascript
JavaScript数组迭代器实例分析
Jun 09 Javascript
js实现图片上传并正常显示
Dec 19 Javascript
关于 jQuery Easyui异步加载tree的问题解析
Dec 06 Javascript
详解axios 全攻略之基本介绍与使用(GET 与 POST)
Sep 15 Javascript
two.js之实现动画效果示例
Nov 06 Javascript
详解javascript中的变量提升和函数提升
May 24 Javascript
js中arguments对象的深入理解
May 14 Javascript
2019年度web前端面试题总结(主要为Vue面试题)
Jan 12 Javascript
基于node+websocket+html实现腾讯课堂聊天室聊天功能
Mar 04 Javascript
关于angular浏览器兼容性问题的解决方案
Jul 26 Javascript
js简单粗暴的发布订阅示例代码
Jan 23 Javascript
Valerio 发布了 Mootools
Sep 23 #Javascript
prototype.js的Ajax对象
Sep 23 #Javascript
在Javascript中为String对象添加trim,ltrim,rtrim方法
Sep 22 #Javascript
如何实现JS函数的重载
Sep 22 #Javascript
扩展String功能方法
Sep 22 #Javascript
js实现ASP分页函数 HTML分页函数
Sep 22 #Javascript
Prototype 1.5.0_rc1 及 Prototype 1.5.0 Pre0小抄本
Sep 22 #Javascript
You might like
php异常处理使用示例
2014/02/25 PHP
jQuery之$(document).ready()使用介绍
2012/04/05 Javascript
javaScript让文本框内的最后一个文字的后面获得焦点实现代码
2013/01/06 Javascript
选择器中含有空格在使用示例及注意事项
2013/07/31 Javascript
JavaScript实现关键字高亮功能
2014/11/12 Javascript
JavaScript入门基础
2015/08/12 Javascript
jQuery实现自动与手动切换的滚动新闻特效代码分享
2015/08/27 Javascript
jquery动态增加删减表格行特效
2015/11/20 Javascript
基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍
2016/05/12 Javascript
JavaScript实现广告弹窗效果
2016/08/09 Javascript
js对象实例详解(JavaScript对象深度剖析,深度理解js对象)
2017/09/21 Javascript
微信小程序实现打开内置地图功能【附源码下载】
2017/12/07 Javascript
Webpack 4如何动态切割JS注入文件名详解
2019/07/09 Javascript
使用JavaScript和MQTT开发物联网应用示例解析
2020/08/07 Javascript
python对json的相关操作实例详解
2017/01/04 Python
Python 多线程实例详解
2017/03/25 Python
python实现mysql的读写分离及负载均衡
2018/02/04 Python
Python构建图像分类识别器的方法
2019/01/12 Python
详解用selenium来下载小姐姐图片并保存
2021/01/26 Python
美国汽车轮胎和轮毂销售网站:Tire Rack
2018/01/11 全球购物
英国领先的高街书籍专家:Waterstones
2018/02/01 全球购物
英国厨房与餐具用品为主的设计品牌:Joseph Joseph
2018/04/26 全球购物
几个Shell Script面试题
2012/08/31 面试题
党支部公开承诺践诺书
2014/03/28 职场文书
中医学专业自荐信范文
2014/04/01 职场文书
2014年党课学习材料
2014/05/11 职场文书
2014年国庆节广播稿
2014/09/19 职场文书
学习党的群众路线教育实践活动心得体会范文
2014/11/03 职场文书
信仰观后感
2015/06/03 职场文书
2016年班主任培训心得体会
2016/01/07 职场文书
2019最新公司租房合同(例文)
2019/07/18 职场文书
Vue中插槽slot的使用方法与应用场景详析
2021/06/08 Vue.js
Django中session进行权限管理的使用
2021/07/09 Python
升级 Win11 还是坚守 Win10?微软 Win11 新系统缺失功能大盘点
2022/04/05 数码科技
python 闭包函数详细介绍
2022/04/19 Python
vue 把二维或多维数组转一维数组
2022/04/24 Vue.js