详解javascript中的事件处理

一.事件传播机制

  客户端JavaScript程序(就是浏览器啦)采用了异步事件驱动编程模型。当文档、浏览器、元素或与之相关的对象发生某些有趣的事情时,Web浏览器就会产生事件(event)。如果JavaScript应用程序关注特定类型的事件,那么它可以注册当这类事件发生时要调用的一个或多个函数。当然了,这种风格并非Web编程独有,所有使用图形用户界面的应用程序都采用了它。

既然要详解事件处理,那我们先从几个基础概念说起吧:

    ①事件类型(event type):是一个用来说明发生什么类型事件的字符串。例如,“mousemove”表示用户移动鼠标,“keydown”表示键盘上某个键被按下。事件类型只是一个字符串,有时候又称之为事件名字(event name);

    ②事件目标(event target):是发生事件或与之相关的对象。Window、Document和Element对象是最常见的事件目标。当然,AJAX中的XMLHttpRequest对象也是一个事件目标;

    ③事件处理程序(event handler):是处理或响应事件的函数,它也叫事件监听程序(event listener)。应用程序通过指明事件类型和事件目标,在Web浏览器中注册它们的事件处理函数。

    ④事件对象(event object):是与特定事件相关且包含有关该事件详细信息的对象。事件对象作为参数传递给事件处理函数(但是在IE8以及其之前版本中,全局变量event才是事件对象)。事件对象都有用来指定事件类型(event type)的type属性和指定事件目标(event target)的target属性(但是在IE8以及其之前版本中,用的是srcElement而非target)。当然,不同类型的事件还会为其相关事件对象定义一些其他的独有属性。例如,鼠标事件的相关对象会包含鼠标指针的坐标,而键盘事件的相关对象会包含按下的键和辅助键的详细信息。

  以上说完了四个基本概念。那么问题来了——如果在一个web页面上用鼠标点击一个元素a的某一子元素b时,应该先执行子元素b注册的事件处理程序还是先执行元素a注册的事件处理程序呢(假设元素a和它的子元素b都有注册事件处理程序)?身为读者的你是否想过这个问题呢?

  这个问题就涉及到浏览器中的事件传播(event propagation)机制。相信大家都听说过事件冒泡(event bubble)和事件捕获(event capturing)吧!没错,它们就是浏览器中的事件传播机制。无图无真相,没有配图?那怎么阔以:

  看了图之后相信你已经大概理解了浏览器中的事件传播机制了:当一个事件发生时,它会先从浏览器顶级对象Window一路向下传递,一直传递到触发这个事件的那个元素,这也就是事件捕获过程。然而,一切并没有结束,事件又从这个元素一路向上传递到Window对象,这也就是事件冒泡过程(但是在IE8以及其之前版本中,事件模型并未定义捕获过程,只有冒泡过程)。

  所以,关于上面的问题,还得看元素a注册的事件处理程序是在捕获过程还是在冒泡过程了。那么到底什么是在捕获过程注册事件处理程序,在冒泡过程注册事件处理程序又是怎么做的呢?这就得好好说说几种注册事件处理程序的方式了:

1. 设置HTML标签属性为事件处理程序

  文档元素的事件处理程序属性,其名字由“on”后面跟着事件名组成,例如:onclick、onmouseover。当然了,这种形式只能为DOM元素注册事件处理程序。实例:

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>test</title>
 <style type="text/css">
 #div1{width: 300px; height: 300px; background: red; overflow:hidden;}
 #div2{margin:50px auto; width: 200px; height: 200px; background: green; overflow:hidden;}
 #div3{margin:50px auto; width: 100px; height: 100px; background: blue;}
 </style>
</head>
<body>
 <div id="div1" onClick="console.log('div1');">div1
 <div id="div2" oNClick="console.log('div2');">div2
 <div id="div3" onclick="console.log('div3');" onclick="console.log('div3333');">div3
 </div>
 </div>
 </div>
<script type="text/javascript">
</script>
</body>
</html>

结果(鼠标点击div3区域后):

从结果中可以看出:

  ①因为HTML里面不区分大小写,所以这里事件处理程序属性名大写、小写、大小混写均可,属性值就是相应事件处理程序的JavaScript代码;

  ②若给同一元素写多个onclick事件处理属性,浏览器只执行第一个onclick里面的代码,后面的会被忽略;

  ③这种形式是在事件冒泡过程中注册事件处理程序的;

2.设置JavaScript对象属性为事件处理程序

  可以通过设置某一事件目标的事件处理程序属性来为其注册相应的事件处理程序。事件处理程序属性名字由“on”后面跟着事件名组成,例如:onclick、onmouseover。实例:

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>test</title>
 <style type="text/css">
 #div1{width: 300px; height: 300px; background: red; overflow:hidden;}
 #div2{margin:50px auto; width: 200px; height: 200px; background: green; overflow:hidden;}
 #div3{margin:50px auto; width: 100px; height: 100px; background: blue;}
 </style>
</head>
<body>
 <div id="div1">div1
 <div id="div2">div2
 <div id="div3">div3
 </div>
 </div>
 </div>
<script type="text/javascript">
 var div1 = document.getElementById('div1');
 var div2 = document.getElementById('div2');
 var div3 = document.getElementById('div3');
  div1.onclick = function(){
    console.log('div1');
  };
  div2.onclick = function(){
    console.log('div2');
  };
  div3.onclick = function(){
    console.log('div3');
  };
  div1.onclick = function(){
    console.log('div11111');
  };

  div1.onClick = function(){
    console.log('DIV11111');
  };

</script>
</body>
</html>

结果(鼠标点击div3区域后):

从结果中可以看出:

  ①因为JavaScript是严格区分大小写的,所以,这种形式下属性名只能按规定小写;

  ②若给同一元素对象写多个onclick事件处理属性,后面写的会覆盖前面的(ps:这就是在修改一个对象属性的值,属性的值是唯一确定的);

  ③这种形式也是在事件冒泡过程中注册事件处理程序的;

3.addEventListener()

  前两种方式出现在Web初期,众多浏览器都有实现。而addEventListener()方法是标准事件模型中定义的。任何能成为事件目标的对象——这些对象包括Window对象、Document对象和所有文档元素等——都定义了一个名叫addEventListener()的方法,使用这个方法可以为事件目标注册事件处理程序。addEventListener()接受三个参数:第一个参数是要注册处理程序的事件类型,其值是字符串,但并不包括前缀“on”;第二个参数是指当指定类型的事件发生时应该调用的函数;第三个参数是布尔值,其可以忽略(某些旧的浏览器上不能忽略这个参数),默认值为false。这种情况是在事件冒泡过程中注册事件处理程序。当其为true时,就是在事件捕获过程中注册事件处理程序。实例:

<!DOCTYPE HTML>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title>test</title>
  <style type="text/css">
    #div1{width: 300px; height: 300px; background: red; overflow:hidden;}
    #div2{margin:50px auto; width: 200px; height: 200px; background: green; overflow:hidden;}
    #div3{margin:50px auto; width: 100px; height: 100px; background: blue;}
  </style>
</head>
<body>
  <div id="div1">div1
    <div id="div2">div2
      <div id="div3">div3
      </div>
    </div>
  </div>
<script type="text/javascript">
  var div1 = document.getElementById('div1');
  var div2 = document.getElementById('div2');
  var div3 = document.getElementById('div3');
  div1.addEventListener('click', function(){ console.log('div1-bubble'); }, false);
  div2.addEventListener('click', function(){ console.log('div2-bubble'); }, false);
  div3.addEventListener('click', function(){ console.log('div3-bubble'); }, false);
  div3.addEventListener('click', function(){ console.log('div3-bubble222'); }, false);
  div1.addEventListener('click', function(){ console.log('div1-capturing'); }, true);
  div2.addEventListener('click', function(){ console.log('div2-capturing'); }, true);
  div3.addEventListener('click', function(){ console.log('div3-capturing'); }, true);
</script>
</body>
</html>

结果(鼠标点击div3区域后):

从结果中可以看出:

  ①addEventListener()第三个参数的作用正如上面所说;

  ②通过addEventListener()方法给同一对象注册多个同类型的事件,并不会发生忽略或覆盖,而是会按顺序依次执行;

相对addEventListener()的是removeEventListener()方法,它同样有三个参数,前两个参数自然跟addEventListener()的意义一样,而第三个参数也只需跟相应的addEventListener()的第三个参数保持一致即可,同样可以省略,默认值为false。它表示从对象中删除某个事件处理函数。实例:

div1.addEventListener('click', div1BubbleFun, false);
div1.removeEventListener('click', div1BubbleFun, false);
function div1BubbleFun(){
 console.log('div1-bubble');
}

4.attachEvent()

  但是,IE8以及其之前版本的浏览器并不支持addEventListener()和removeEventListener()。相应的,IE定义了类似的方法attachEvent()和detachEvent()。因为IE8以及其之前版本浏览器也不支持事件捕获,所以attachEvent()并不能注册捕获过程中的事件处理函数,因此attachEvent()和detachEvent()要求只有两个参数:事件类型和事件处理函数。而且,它们的第一个参数使用了带“on”前缀的事件处理程序属性名。实例:

var div1 = document.getElementById('div1');
div1.attachEvent('onclick', div1BubbleFun);
function div1BubbleFun(){
  console.log('div1-bubble');
}

  相应的,从对象上删除事件处理程序函数使用detachEvent()。例如:

div1.detachEvent('onclick', div1BubbleFun);

  到此为止,我们已经说了浏览器中事件传播机制以及各种注册事件处理程序的方法。下面我们就再说说事件处理程序调用时的一些问题吧!

二.事件处理程序的调用

1.事件处理程序的参数:正如前面所说,通常事件对象作为参数传递给事件处理函数,但IE8以及其之前版本的浏览器中全局变量event才是事件对象。所以,我们在写相关代码时应该注意兼容性问题。实例(给页面上id为div1的元素添加点击事件,当点击该元素时在控制台输出事件类型和被点击元素本身):

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>test</title>
 <style type="text/css">
 #div1{width: 300px; height: 300px; background: red; overflow: hidden;}
 </style>
</head>
<body>
 <div id="div1">div1</div>
 <script type="text/javascript">
 var div1 = document.getElementById('div1');
 if(div1.addEventListener){
 div1.addEventListener('click', div1Fun, false);
 }else if(div1.attachEvent){
 div1.attachEvent('onclick', div1Fun);
 }
 function div1Fun(event){
 event = event || window.event;
 var target = event.target || event.srcElement;
 console.log(event.type);
 console.log(target);
 }
 </script>
</body>
</html>

2.事件处理程序的运行环境:关于事件处理程序的运行环境,也就是在事件处理程序中调用上下文(this值)的指向问题,可以看下面四个实例。

实例一:

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>test</title>
 <style type="text/css">
 #div1{width: 300px; height: 300px; background: red; overflow: hidden;}
 </style>
</head>
<body>
 <div id="div1" onclick="console.log('html:'); console.log(this);">div1</div>
 <script type="text/javascript">
 </script>
</body>
</html>

  结果一:

  从结果可以看出:

    ①第一种方法事件处理程序中this指向这个元素本身;

实例二:

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>test</title>
 <style type="text/css">
 #div1{width: 300px; height: 300px; background: red; overflow: hidden;}
 </style>
</head>
<body>
 <div id="div1" onclick="console.log('html:'); console.log(this);">div1</div>
 <script type="text/javascript">
 var div1 = document.getElementById('div1');
 div1.onclick = function(){
 console.log('div1.onclick:');
 console.log(this);
 };
 </script>
</body>
</html>

  结果二:

  从结果可以看出:

    ①第二种方法事件处理程序中this也指向这个元素本身;

    ②存在第二种方法时,它会覆盖第一种方法注册的事件处理程序;

实例三:

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>test</title>
 <style type="text/css">
 #div1{width: 300px; height: 300px; background: red; overflow: hidden;}
 </style>
</head>
<body>
 <div id="div1" onclick="console.log('html:'); console.log(this);">div1</div>
 <script type="text/javascript">
 var div1 = document.getElementById('div1');
 div1.onclick = function(){
 console.log('div1.onclick:');
 console.log(this);
 };
 div1.addEventListener('click', function(){
 console.log('div1.addEventListener:');
 console.log(this);
 }, false);
 </script>
</body>
</html>

  结果三:

  从结果可以看出:

    ①第三种方法事件处理程序中this也指向这个元素本身;

    ②第三种方法并不会覆盖第一种或第二种方法注册的事件处理程序;

实例四:

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>test</title>
 <style type="text/css">
 #div1{width: 300px; height: 300px; background: red; overflow: hidden;}
 </style>
</head>
<body>
 <div id="div1" onclick="console.log('html:'); console.log(this);">div1</div>
 <script type="text/javascript">
 var div1 = document.getElementById('div1');
 div1.onclick = function(){
 console.log('div1.onclick:');
 console.log(this);
 };
 div1.attachEvent('onclick', function(){
 console.log('div1.attachEvent:');
 console.log(this === window);
 });

 </script>
</body>
</html>

  结果四:

  从结果可以看出:

    ①第四种方法事件处理程序中this指向全局对象Window;

    ②第四种方法也不会覆盖第一种或第二种方法注册的事件处理程序;

3.事件处理程序的调用顺序:多个事件处理程序调用规则如下:

  ①通过HTML属性注册的处理程序和通过设置对象属性的处理程序一直优先调用;

  ②使用addEventListener()注册的处理程序按照它们的注册顺序依次调用;

  ③使用attachEvent()注册的处理程序可能按照任何顺序调用,所以代码不应该依赖于调用顺序;

4.事件取消:

①取消事件的浏览器默认操作(比如点击超链接元素会自动发生页面跳转的默认操作):如果使用前两种方法注册事件处理程序,可以在处理程序中添加返回值false来取消事件的浏览器默认操作。在支持addEventListener()的浏览器中,也可以通过调用事件对象的preventDefault()方法取消事件的默认操作。至于IE8及其之前的浏览器可以通过设置事件对象的returnValue属性为false来取消事件的默认操作。参考代码:

function cancelHandler(event){
 var event = event || window.event;
 if(event.preventDefault){
 event.preventDefault();
 }
 if(event.returnValue){
 event.returnValue = false;
 }
 return false;
}

②取消事件传播:在支持addEventListener()的浏览器中,可以调用事件对象的一个stopPropagation()方法阻止事件的继续传播,它能工作在事件传播期间的任何阶段(捕获期阶段、事件目标本身、冒泡阶段);但是在IE8以及其之前版本的浏览器中并不支持stopPropagation()方法,而且这些浏览器也不支持事件传播的捕获阶段,相应的,IE事件对象有一个cancelBubble属性,设置这个属性为true能阻止事件进一步传播(即阻止其冒泡)。参考代码(阻止发生在div3区域的点击事件冒泡到div2和div1):

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>test</title>
 <style type="text/css">
 #div1{width: 300px; height: 300px; background: red; overflow:hidden;}
 #div2{margin:50px auto; width: 200px; height: 200px; background: green; overflow:hidden;}
 #div3{margin:50px auto; width: 100px; height: 100px; background: blue;}
 </style>
</head>
<body>
 <div id="div1">div1
 <div id="div2">div2
 <div id="div3">div3
 </div>
 </div>
 </div>
 <script type="text/javascript">
 var div1 = document.getElementById('div1');
 var div2 = document.getElementById('div2');
 var div3 = document.getElementById('div3');
    div1.onclick = function(){
 console.log('div1');
    };
    div2.onclick = function(){
 console.log('div2');
    };
    div3.onclick = function(event){
 stopEventPropagation(event);
 console.log('div3');
    };

 function stopEventPropagation(event){
 var event = event || window.event;
 if(event.stopPropagation){
 event.stopPropagation();
 }else{
 event.cancelBubble = true;
 }
 }
 </script>
</body>
</html>

以上就是javascript事件处理的全部介绍,当然,关于事件冒泡还是有可利用之处的,这也就是我们常说的事件代理或者事件委托,对于这方面知识以后会陆续更新。

(0)

相关推荐

  • JavaScript事件处理的方式(三种)

    最近这段时间因为每天要修改网站,为网站做特效,所以看了很多的js接触事件,自己只会使用一小部分,有时用的时候也比较混乱,现在系统的整理了一下,特此分享到我们平台供大家参考下! 一.什么是JavaScript事件? 事件(Event)是JavaScript应用跳动的心脏,也是把所有东西粘在一起的胶水,当我们与浏览器中Web页面进行某些类型的交互时,事件就发生了. 事件可能是用户在某些内容上的点击.鼠标经过某个特定元素或按下键盘上的某些按键,事件还可能是Web浏览器中发生的事情,比如说某个Web页面

  • javascript 处理事件绑定的一些兼容写法

    绑定事件 复制代码 代码如下: var addEvent = function( obj, type, fn ) { if (obj.addEventListener) obj.addEventListener( type, fn, false ); else if (obj.attachEvent) { obj["e"+type+fn] = fn; obj.attachEvent( "on"+type, function() { obj["e"

  • 轻松创建nodejs服务器(5):事件处理程序

    为了对不同请做出不同的反馈,我们引入一个事件处理器的模块. 该模块命名为 requestHandlers,我们先添加start() 和 upload()两个占位函数. requestHandlers.js 代码如下: 复制代码 代码如下: function start() {     console.log("访问/star时调用这个."); }   function upload() {     console.log("访问/upload时调用这个."); }

  • 详细解读JavaScript的跨浏览器事件处理

    一.关于获取事件对象 FF有点倔强,只支持arguments[0],不支持window.event.这次真的不怪IE,虽然把event作为window的属性不合规范,但大家都已经默许这个小问题存在了,只有FF这么多年了还是特立独行.所以,跨浏览器的事件对象获取有以下两种方式: 带参的: getEvent : function(event){ return event ? event : window.event; //return event || window.event;//或者更简单的方式

  • js event事件的传递与冒泡处理

    复制代码 代码如下: <div> <table nclick="gotClick(event,'table',this)" id="table"> <tr nclick="gotClick(event,'tr',this)" id="tr"> <td nclick="gotClick(event,'td',this)" id="td"> &

  • 浅谈Javascript事件处理程序的几种方式

    事件就是用户或浏览器自身执行的某种动作.比如说click,mouseover,都是事件的名字.而相应某个事件的函数就叫事件处理程序(或事件侦听器).为事件指定处理程序的方式有好几种. 一:HTML事件处理程序. 如: 复制代码 代码如下: <script type="text/javascript"> function show(){ alert('hello world!'); } </script> <input type="button&q

  • JavaScript中的事件处理

    事件处理概述  事件处理是对象化编程的一个很重要的环节,没有了事件处理,程序就会变得很死,缺乏灵活性.事件处理的过程可以这样表示:发生事件 - 启动事件处理程序 - 事件处理程序作出反应.其中,要使事件处理程序能够启动,必须先告诉对象,如果发生了什么事情,要启动什么处理程序,否则这个流程就不能进行下去.事件的处理程序可以是任意 JavaScript 语句,但是我们一般用特定的自定义函数(function)来处理事情. 指定事件处理程序有三种方法: 方法一 直接在 HTML 标记中指定.这种方法是

  • 引用其它js时如何同时处理多个window.onload事件

    有时引用其它js时,其js却使用了window.onload事件,这样的话,引入的页面的onload事件就有可能执行不了,怎样才能两个都运行呢?除了将两个写到一块儿去的方法外,还有其他的方法 if(window.onload!=null){ eval("theOldFun="+window.onload.toString()); window.onload=function(){theOldFun();addReadResource();}; } eval()函数的作用: 它的功能是把

  • js onload处理html页面加载之后的事件

    复制代码 代码如下: <script type="text/javascript"> window.onload=function(){ alert("加载完毕") } </script>

  • 用JavaScript事件串连执行多个处理过程的方法

    最近用到JavaScript 事件处理机制,找了些资料. 以前写 JavaScript 程序时,事件都是采用  复制代码 代码如下: object.event = handler; 的方式初始化.这种方式对于 Internet Explorer.Mozilla/Firefox 和 Opera 来说很通用.但是有一个问题就是,这种方式只能一个事件对应一个事件处理过程.如果希望一个事件可以依次执行多个处理过程就不好用了. 但是 Internet Explorer 从 5.0 开始提供了一个 atta

  • Ext javascript建立超链接,进行事件处理的实现方法

    1,如何在javasript建立超链接 <script type="text/JavaScript"> //方法一: location.href='网址'; //方法二: document.write('<a href="网址">文字</a>'); </script> 2,应用到Ext中的树控件事件处理 tree_03.js 复制代码 代码如下: Ext.onReady(function(){ var root = n

  • JavaScript入门教程(11) js事件处理

    事件处理概述 事件处理是对象化编程的一个很重要的环节,没有了事件处理,程序就会变得很死,缺乏灵活性.事件处理的过程可以这样表示:发生事件 - 启动事件处理程序 - 事件处理程序作出反应.其中,要使事件处理程序能够启动,必须先告诉对象,如果发生了什么事情,要启动什么处理程序,否则这个流程就不能进行下去.事件的处理程序可以是任意 JavaScript 语句,但是我们一般用特定的自定义函数(function)来处理事情.指定事件处理程序有三种方法:方法一 直接在 HTML 标记中指定.这种方法是用得最

随机推荐