事件

DOM 的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象,比如XMLHttpRequest,也部署了这个接口。
该接口主要提供三个实例方法。

  • addEventListener: 绑定事件
  • removeEventListener: 移除事件
  • dispatchEvent: 触发事件

addEventListener为例

btn.addEventListener('click',function(){console.log(this)},false)

第三个参数默认为false,可省略,指该事件只在冒泡阶段触发;若为true,则为在捕获阶段。
addEventListener方法可以为针对当前对象的同一个事件,添加多个不同的监听函数。这些函数按照添加顺序触发,即先添加先触发。
用队列理解,先进先出。

  • 进:addEventListener
  • 出:removeEventListener

如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除(不必使用removeEventListener方法手动去除)。

注意,removeEventListener方法移除的监听函数,必须是addEventListener方法添加的那个监听函数,而且必须在同一个元素节点,否则无效。

div.addEventListener('click', function (e) {}, false);
div.removeEventListener('click', function (e) {}, false);

上面代码中,removeEventListener方法无效,因为监听函数不是同一个匿名函数。

监听函数

浏览器的事件模型,就是通过监听函数对事件做出反应。事件发生后,浏览器听到了这个事件,就会执行相应的监听函数。这就是事件驱动编程模式的主要编程方式。
JavaScript 有三种方法,可以为事件绑定监听函数。

1. addEventListener (推荐这种)

所有 DOM 节点实例都有addEventListener方法,用来为该节点定义事件的监听函数。

window.addEventListener('load', doSomething, false);

相比另外两种有如下优点:

  • 同一个事件可以添加多个监听函数。
  • 能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数。
  • 除了 DOM 节点,其他对象(比如window、XMLHttpRequest等)也有这个接口,它等于是整个 JavaScript 统一的监听函数接口。

2. 元素节点的事件属性

元素节点对象的事件属性,同样可以指定监听函数。

window.onload = doSomething;

div.onclick = function (event) {
  console.log('触发事件');
};

使用这个方法指定的监听函数,也是只会在冒泡阶段触发。

注意,这种方法与 HTML 的on-属性的差异是,它的值是函数名doSomething,而不像后者,必须给出完整的监听代码doSomething()

同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。因此,也不推荐使用。

3. HTML 的 on- 属性(不推荐)


上面代码为body节点的load事件、div节点的click事件,指定了监听代码。一旦事件发生,就会执行这段代码。

注意,这些属性的值是将会执行的代码,而不是一个函数。

一旦指定的事件发生,on-属性的值是原样传入 JavaScript 引擎执行。因此如果要执行函数,不要忘记加上一对圆括号。

对象this、currentTarget和target

在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则this、currentTarget和target包含相同的值。

1 var btn = document.getElementById("myBtn");
2 btn.onclick = function (event) {
3     alert(event.currentTarget === this); //ture
4     alert(event.target === this); //ture
5 };

这个例子检测了currentTarget和target与this的值。由于click事件的目标是按钮,一次这三个值是相等的。如果事件处理程序存在于按钮的父节点中,那么这些值是不相同的。

1 document.body.onclick = function (event) {
2     alert(event.currentTarget === document.body); //ture
3     alert(this === document.body); //ture
4     alert(event.target === document.getElementById("myBtn")); //ture
5 };

当单击这个例子中的按钮时,this和currentTarget都等于document.body,因为事件处理程序是注册到这个元素的。然而,target元素却等于按钮元素,以为它是click事件真正的目标。由于按钮上并没有注册事件处理程序,结果click事件就冒泡到了document.body,在那里事件才得到了处理。

currentTarget始终是监听事件者,而target是事件的真正发出者。

注意,在jQuery提供的on方法中,e.currentTarget与该方法接收的第二个参数有关,根据jQuery的文档描述

如果省略selector或者是null,那么事件处理程序被称为直接事件 或者 直接绑定事件 。每次选中的元素触发事件时,就会执行处理程序,不管它直接绑定在元素上,还是从后代(内部)元素冒泡到该元素的
当提供selector参数时,事件处理程序是指为委派事件(事件委托或事件代理)。事件不会在直接绑定的元素上触发,但当selector参数选择器匹配到后代(内部元素)的时候,事件处理函数才会被触发。jQuery 会从 event target 开始向上层元素(例如,由最内层元素到最外层元素)开始冒泡,并且在传播路径上所有绑定了相同事件的元素若满足匹配的选择器,那么这些元素上的事件也会被触发。




  
  
  JS Bin
  


  
  • hello 1
  • hello 1
  • hello 1
  • hello 1

当li中含有子元素的时候,e.target指的是触发事件的元素,可能是span也可能是li,此时的e.currentTarget指的是selector那个参数,也就是本例中的li。如果省略selector参数,那么它和addEventListener中e.target和e.currentTarget是一致的。

事件委托

事件委托就是利用事件冒泡机制,指定一个事件处理程序,来管理某一类型的所有事件。
举个取快递的例子:
公司的员工们经常会收到快递。为了方便签收快递,有两种办法:一种是快递到了之后收件人各自去拿快递;另一种是委托前台MM代为签收,前台MM收到快递后会按照要求进行签收。
很显然,第二种方案更为方便高效,同时这种方案还有一种优势,那就是即使有新员工入职,前台的MM都可以代替新员工签收快递。
这个例子之所以非常恰当形象,是因为这个例子包含了委托的两层意思:首先,现在公司里的员工可以委托前台MM代为签收快递,即程序中现有的dom节点是有事件的并可以进行事件委托;其次,新入职的新员工也可以让前台MM代为签收快递,即程序中新添加的dom节点也是有事件的,并且也能委托处理事件。

如果一个ul中有100li,每个li都需要处理click事件,我们可以遍历所有li,给它们添加事件处理程序,这并不是理想的解决方案。
事件委托怎么实现呢?因为冒泡机制,既然点击子元素时,也会触发父元素的点击事件。那么我们就可以把点击子元素的事件要做的事情,交给最外层的父元素来做,让事件冒泡到最外层的dom节点上触发事件处理程序,这就是事件委托。

你可能感兴趣的:(事件)