JavaScript事件对象、事件流和事件代理

1 事件对象

事件在浏览器中是以对象的形式存在的,即event。触发一个事件,就会产生一个事件对象event,该对象包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。
所有浏览器都支持event对象,但支持方式不同,在DOM中event对象必须作为唯一的参数传给事件处理函数,在IE中event是window对象的一个属性。

DOM中事件对象重要属性和方法。
属性:

  • type属性,用于获取事件类型
  • target属性 用户获取事件目标 事件加在哪个元素上。(更具体target.nodeName)

方法:

  • stopPropagation()方法 用于阻止事件冒泡
  • preventDefault()方法 阻止事件的默认行为 移动端用的多

IE中的事件对象

  • 通过DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。
  • 第二种情况:通过attachEvent()添加的事件处理程序,event对象作为参数传入。

属性:

  • type属性,用于获取事件类型(一样)
  • srcElement属性,用户获取事件目标 事件加在哪个元素上。
  • cancelBubble属性 用于阻止事件冒泡 IE中cancelBubble为属性而不是方法,true表示阻止冒泡。
  • returnValue属性 阻止事件的默认行为 false表示阻止事件的默认行为。

Event对象的一些兼容性写法:

  • 获得event对象兼容性写法
    event || (event = window.event);
  • 获得target兼容型写法
    event.target||event.srcElement
  • 阻止浏览器默认行为兼容性写法
    event.preventDefault ? event.preventDefault() : (event.returnValue = false);
  • 阻止冒泡写法
    event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true);

2 事件流

事件流描述的是从页面中接收事件的顺序。事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流。

事件传播的顺序对应浏览器的两种事件流模型:捕获型事件流和冒泡型事件流。
冒泡型事件流:事件的传播是从最特定的事件目标到最不特定的事件目标。即从DOM树的叶子到根。
捕获型事件流:事件的传播是从最不特定的事件目标到最特定的事件目标。即从DOM树的根到叶子。
事件捕获的思想就是不太具体的节点应该更早接收到事件,而最具体的节点最后接收到事件。
DOM标准采用捕获+冒泡。两种事件流都会触发DOM的所有对象,从document对象开始,也在document对象结束。

DOM标准规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。如图:
这里写图片描述
事件捕获阶段:实际目标(div)在捕获阶段不会接收事件。事件从document到html再到body就停止了。上图中为1~3。
处于目标阶段:事件在目标上发生并处理。但是事件处理会被看成是冒泡阶段的一部分。
冒泡阶段:事件又传播回文档。
注意:

  • 尽管“DOM2级事件”标准规范明确规定事件捕获阶段不会涉及事件目标,但是在IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两次机会在目标对象上面操作事件。
  • 并非所有的事件都会经过冒泡阶段 。所有的事件都要经过捕获阶段和处于目标阶段,但是有些事件会跳过冒泡阶段:如,获得输入焦点的focus事件和失去输入焦点的blur事件。
    示例:
 <body>
    <div id="firstDiv">
        <div id="secondDiv">
            <button id="button1" class="clickMe">Click me</button>
        </div>
    </div>
    <script>    
        var firstDiv = document.getElementById("firstDiv"); 
        var secondDiv = document.getElementById("secondDiv");   
        var btn = document.getElementById("button1");   
        firstDiv .addEventListener('click',function(e){
            alert("firstDiv的click事件在冒泡阶段被触发,id="+this.id);
        },false);
        firstDiv .addEventListener('click',function(e){
            alert("firstDiv的click事件在捕获阶段被触发,id="+this.id);
        },true);
        secondDiv.addEventListener('click',function(e){
            alert("secondDiv的click事件在冒泡阶段被触发,id="+this.id);
        },false);
        secondDiv.addEventListener('click',function(e){
            alert("secondDiv的click事件在捕获阶段被触发,id="+this.id);
        },true);            
        btn.addEventListener('click',function(e){
            alert("button1的click事件在捕获阶段被触发,id="+this.id);
        },true);
        btn.addEventListener('click',function(e){
            alert("button1的click事件在冒泡阶段被触发,id="+this.id);
        },false);
    </script>
 </body>

虽然两次机会在目标对象上面操作事件,但其执行顺序却与代码的顺序相关,并非按照先捕获后冒泡的顺序。
这里写图片描述
这里写图片描述

3 事件处理程序##

事件就是用户或浏览器自身执行的某种动作。比如click,mouseup,keydown,mouseover等都是事件的名字。而响应某个事件的函数就叫事件处理程序(事件监听器),事件处理程序以on开头,比如click的事件处理程序就是onclick。

DOM 0级事件处理程序

DOM 0级事件处理程序:把一个函数赋值给一个事件的处理程序属性。
例如:

<input type="button" value="按钮" id="btn"/>
var oBtn=document.getElementById('btn');   //获得oBtn按钮对象
oBtn.onclick      //给oBtn添加onclick属性,属性又触发了一个事件处理程序
oBtn.onclick=function(){  }  //添加匿名函数
oBtn.onclick=null      //删除onclick属性

DOM 2级事件处理程序

DOM 2级事件定义了两个方法,用于指定和删除事件处理程序的操作。addEventListener()和removeEventListener()。需要三个参数:事件名称要分配的函数处理函数是用于冒泡阶段(false)还是捕获阶段(true),默认为冒泡阶段false。

4 事件代理

事件代理的原理用到的就是事件冒泡和目标元素,把事件处理器添加到父元素,等待子元素事件冒泡,并且父元素能够通过target(IE为srcElement)判断是哪个子元素,从而做相应处理。

示例:

<body>
<ul id="color-list">
<li>red</li>
<li>orange</li>
<li>yellow</li>
<li>green</li>
<li>blue</li>
<li>indigo</li>
<li>purple</li>
</ul>
<script>
(function(){
    var colorList=document.getElementById("color-list");
    colorList.addEventListener('click',showColor,false);
    function showColor(e)
    {
        e=e||window.event;
        var targetElement=e.target||e.srcElement;
        if(targetElement.nodeName.toLowerCase()==="li"){
        alert(targetElement.innerHTML);
        }
    }
})();
</script>
</body>

事件代理的好处

  • 将多个事件处理器减少到一个,因为事件处理器要驻留内存,这样就提高了性能。想象如果有一个100行的表格,对比传统的为每个单元格绑定事件处理器的方式和事件代理(即table上添加一个事件处理器),不难得出结论,事件代理确实避免了一些潜在的风险,提高了性能。
  • DOM更新无需重新绑定事件处理器,因为事件代理对不同子元素可采用不同处理方法。如果新增其他子元素(a,span,div等),直接修改事件代理的事件处理函数即可,不需要重新绑定处理器,不需要再次循环遍历。

猜你喜欢

转载自blog.csdn.net/shiyangxu/article/details/81483995
今日推荐