Javascript的事件机制

事件流

事件流描述的是元素接收事件的顺序。

  • 事件冒泡:事件从最具体/最内层的元素开始接受,向上传递至最外层的元素节点(document),IE的事件流。
  • 事件捕获:最外层的节点最先接收到事件,逐层传递到最内层的节点。
DOM2级事件流

DOM2级规定事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。处于目标阶段是指实际的事件目标接收到事件,再后续的事件处理阶段,它被看作是事件冒泡的一部分。
这里写图片描述

事件处理程序

HTML事件处理程序

通过指定HTML的特性,如onclick属性来为元素指定事件。在事件冒泡阶段被处理。

<input type="button" value="Click Me" onclick="alert('Clicked')" />
//此时,函数内部,this指向目标元素
 <script type="text/javascript">
        function showMessage(){
            alert("Hello world!");
        }
 </script>
 <input type="button" value="Click Me" onclick="showMessage()" />
缺点
  • 加载时差问题:html元素出现时,可能js代码还未加载,此时如果用户执行了事件,则会报错。解决方法为,再执行函数中添加try…catch语句,捕获错误;
  • JavaScript代码与HTML紧密耦合;
  • 在不同的浏览器中的作用域链可能不同。
DOM0级事件处理程序

将函数赋值给一个事件处理程序属性。在事件冒泡阶段被处理。

var btn = document.getElementById("myBtn");
//函数中的this指向绑定的元素。
btn.onclick = function(){
    alert(this.id);
};
//删除事件的方法
btn.onclick = null;
优点
  • 被所有浏览器支持,具有跨浏览器优势。
缺点
  • 为事件处理程序属性指定两个函数时,后添加的事件处理方法会覆盖前面添加的。
DOM2级事件处理程序

定义了addEventListener()和removeEventListener()两个方法,来添加或删除事件处理程序。接受三个参数:

  • 要处理的事件名,如, ‘click’
  • 作为事件处理程序的函数
  • 在捕获阶段(true)还是冒泡阶段(false)调用事件处理程序
btn.addEventListener("click", function(){
    //函数的作用域与元素的作用域一致
    alert("Hello world!");
}, false);
注意
  • 通过addEventListener()添加的方法只能通过removeEventListener()来移除。移除时,传入的三个参数必须一致。如果添加时第二个参数使用的是匿名函数,则无法移除。
优点
  • 可以为同一元素的同一事件添加多个事件处理程序,按照事件的添加顺序触发。
缺点
  • 不兼容IE9以下的浏览器,IE9及以后的可兼容。
IE事件处理程序

IE9以下不兼容DOM2级事件处理程序,但它实现了两个类似的方法:attachEvent()和detachEvent()。接受两个参数:

  • 事件处理程序的名称,如 “onclick”
  • 事件处理程序函数
btn.attachEvent("onclick", function(){
    alert("Clicked");
});
注意
  • attachEvent添加的事件只能在事件冒泡阶段执行
  • attachEvent的第一参数为”onclick”,而addEventListener()的第一个参数为”click”
  • attachEvent绑定的函数在全局作用域中运行,函数中的this指向window
  • 可以通关过attachEvent为元素添加多个事件处理程序,但会按照与添加顺序相反的顺序执行
跨浏览器的事件处理程序

综合上述各事件处理程序的优缺点,实现跨浏览器的事件处理方法:

var EventUtil = {
    //添加事件
    addHandler: function(element, type, handler){
        if (element.addEventListener){
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent){
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    //移除事件
    removeHandler: function(element, type, handler){
        if (element.removeEventListener){
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent){
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    }
};

事件对象

在触发DOM元素的某个事件时,会产生一个事件对象event,作为参数传递给事件响应函数。

DOM中的事件对象

使用DOM0级和DOM2级添加事件时,都会传递事件对象。该对象的主要属性如下:

属性/方法说明
type被触发的事件类型,如”click”
target事件目标,如button元素
currentTarget事件处理程序当前正在处理事件的元素,该事件可能是从target元素冒泡传递过来的
preventDefault()阻止事件的默认行为
stopPropagation()阻止事件进一步捕获或冒泡
eventPhase调用事件的结算,1表示捕获,2表示处于目标,3表示冒泡
cancelable是否可以取消事件的默认行为,只有为true时才能调用preventDefault()函数
IE中的事件对象

IE中的事件对象取决于指定事件处理程序的方法。
如果使用DOM0级的方法只当事件处理程序,那么event对象时window对象的一个属性:

btn.onclick = function(){
    var event = window.event;
    alert(event.type);//'click'
}

如果使用attachEvent的方法绑定事件处理程序,则会传递一个event对象,此时,window.event与传入的event指向同一个对象,两者都可以使用。
IE中的event对象具有如下属性:

属性/方法描述
cancelBubble默认为false,设置为true时可以取消冒泡,相当于DOM中的stopPropagation()方法
returnValue默认为true,设置为false时可以取消默认行为,相当于DOM中的preventDefault()方法
srcElement事件目标,同DOM中的target
type事件类型
跨浏览器的事件对象
var EventUtil = {
     //添加事件处理程序
    addHandler: function(element, type, handler){
      //...
    },

    //获取事件对象
    getEvent: function(event){
        return event ? event : window.event;
    },
    //获取事件目标
    getTarget: function(event){
        return event.target || event.srcElement;
    },   
    //阻止事件的默认行为
    preventDefault: function(event){
        if (event.preventDefault){
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    //移除事件
    removeHandler: function(element, type, handler){
        //...
    },
    //阻止事件冒泡
    stopPropagation: function(event){
        if (event.stopPropagation){
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

事件代理

事件代理,又叫做事件委托,即利用浏览器的事件冒泡机制,只用指定一个事件,就可以管理某一类型的所有事件的方法。事件代理可以用于解决文档中事件处理程序过多的问题。

举个栗子,假如我们有以下HTML代码,我们需要实现的功能是在单机每个列表项的时候,弹出每个列表项中的文本内容。

<ul id="myLinks">
    <li id="goSomewhere">Go somewhere</li>
    <li id="doSomething">Do something</li>
    <li id="sayHi">Say hi</li>
</ul>

按照传统的方法,我们需要为上述每个<li>标签都添加一个单击事件。设想在列表项很多的情况下,这种方法是很不可取的,我们将会使用很多的代码用于添加事件处理程序。

而利用事件代理的思路是,我们只需要在<ul>标签上添加一个事件处理程序就好,由于<li>标签是<ul>的子标签,所有发生在<li>标签上的事件都可以冒泡到<ul>标签上,被<ul>标签捕获,并通过事件的event对象判断事件的target,并针对不同的target进行不同的处理。利用事件代理机制可以使用更少的时间,和空间来处理事件处理程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值