JavaScript 事件

本文详细介绍了事件流的概念,包括事件冒泡与事件捕获两种不同的处理方式,并探讨了HTML事件处理程序、DOM0级及DOM2级事件处理程序的区别。此外还讨论了IE事件处理程序的特点,并给出了事件模拟与委托的实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事件流

事件流描述的是从页面中接收事件的顺序。IE的事件流是事件冒泡流,Netscape的事件流是事件捕获流。
事件冒泡流:嵌套最深的结点最先接收事件。
事件捕获流:document对象最先接收事件。

var test = function (el){
    el.addEventListener('click', function() {
        console.log(el.id);
    },false);
    el.addEventListener('click', function() {
        console.log(el.id);
    },true);
}

var one = document.getElementById('one');
var two = document.getElementById('two');
var three = document.getElementById('three');
var ip = document.getElementById('input');
test(one);
test(two);
test(three);
test(ip);

输出:
one
two
three
input
input
three
two
one

HTML事件处理程序

在HTML中,某个元素支持每种事件,都可以使用一个与之相应事件的处理程序同名的HTML特性来指定。
独到之处
首先,这样会创建一个封装着元素属性值的函数。这个函数中有一个局部变量event也就是事件对象。在这个函数内部,this值等于事件的目标元素。
两个缺点
首先存在一个时差问题,因为用户可能会在HTML元素一出现在页面上就触发相应的事件,但当时事件的处理程序有可能尚不具备执行条件。为此,很多html事件都会用try{}catch(ex){}来封装。
第二,HTML与JavaScript紧密耦合。

书中提到使用with,来扩展作用域,而《JavaScript精萃》里说

with的本意是减少键盘输入。比如
  obj.a = obj.b;
  obj.c = obj.d;
可以简写成
  with(obj) {
    a = b;
    c = d;
  }
但是,在实际运行时,解释器会首先判断obj.b和obj.d是否存在,如果不存在的话,再判断全局变量b和d是否存在。这样就导致了低效率,而且可能会导致意外,因此最好不要使用with语句。

DOM0级事件处理程序

将一个函数赋值给一个事件处理程序属性。以这种方式添加的事件处理程序会在冒泡阶段被处理。

document.getElementById('myButton').onclick = function(){
    console.log(this.id);
};
document.getElementById('myButton').onclick = null;  //删除事件处理程序

注意,在这些代码运行以前不会指定事件处理程序,因此如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么单击都没有反应。
使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行,换句话说,程序中的this引用当前元素。

DOM2级事件处理程序

addEventListenerremoveEventListener
使用DOM2级方法的好处在于可以为同一个事件添加多个事件处理程序。
使用addEventListener添加的事件处理程序,只能用removeEventListener删除,且匿名函数无法删除。

IE事件处理程序

IE实现了与DOM中类似的两个方法:attachEvent()detachEvent()只接受2个参数,IE只提供冒泡流。
与DOM0级方法的主要区别在于事件处理程序的作用域。在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,此时this等于window。

document.getElementById('myButton').attachEvent("onclick",function(){
    alert("first");
})
document.getElementById('myButton').attachEvent("onclick",function(){
    alert("two")
})

同时,IE的事件处理程序不是以添加他们的顺序执行,而是以相反的顺序被触发。
dc
在以上中使用addEventListenerattachEvent,最好不要使用匿名函数,因为去除时,任然需要将函数输入,匿名函数无法成功去除。

《JavaScript精粹》中也有相关建议如下:
在Javascript中定义一个函数,有两种写法:
  function foo() { }

  var foo = function () { }
两种写法完全等价。但是在解析的时候,前一种写法会被解析器自动提升到代码的头部,因此违背了函数应该先定义后使用的要求,所以建议定义函数时,全部采用后一种写法。

内存与性能

在每个对象上绑定事件,即会增加dom的访问次数,而且也会大大增加event对象,造成内存占用。所以想要提高性能,就会用到委托事件。
建立在冒泡机制之上的事件委托技术,可以有效的减少事件处理程序的数量,能够大大的提高性能,减少内存消耗。
在两种情况下,需要注意移除事件处理程序,第一种就是从文档中移除带有事件处理程序的元素时,第二种情况是卸载页面的时候。

利用事件委托实现事件在HTML页面中的可配置

    var list = document.getElementById("mylinks");
    list.addEventListener("click", function (event) {
        switch(event.target.id){
            case "github":
                location.href="https://github.com/";
            case "baidu":
                location.href="https://baidu.com/";
            case "google":
                location.href="https://google.com/";
        }

    });

事件模拟

事件模拟分为:
- UIEvents
- MouseEvents
- MutationEvents
- HTMLEvents

    var btn = document.getElementById("myButton");
    var event = document.createEvent("MouseEvents");
    event.initEvent('click');
    btn.dispatchEvent(event);  //模拟在btn上触发event事件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值