前言:在一张纸上画一个同心圆,如果把手指放在圆心上,那么你的手指指向的是纸上的所有圆。如下图如果你单击了start按钮,你也单击了按钮的容器元素(绿色盒子和红色盒子),甚至也单击了整个页面
**
事件流
描述的是从页面中接收事件的顺序,但是IE和Netscape Communicator开发团队关于事件流的概念是完全相反的。IE 的事件流是事件冒泡流,Netscape 则是事件捕获流
事件冒泡(推荐)
事件开始时由具体的元素接收(上图中的 start 按钮),然后逐级向上传播到较为不具体的节点。 (start 按钮 -> 绿色容器->红色容器->body->html->document)
事件捕获(特殊需要时使用)
不太具体的节点应该更早接收到事件,而最具体的节点最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。(document->html->body->红色容器->绿色容器->start 按钮)
DOM 事件流
DOM事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
事件委托
事件委托:通过指定一个事件处理程序,达到管理某一类型的所有事件。
<ul id="myTask">
<li id="task1">
click me to do task1
</li>
<li id="task2">
click me to do task2
</li>
<li id="task3">
click me to do task3
</li>
</ul>
如上所示, 如果我们对每一个li 元素都添加一个onclick 事件的话, 需要添加三个事件处理程序。首先,每个函数都是对象,都会占用内存,内存中的对象越多,性能越差。其次事先指定所有事件处理程序会导致DOM 的访问次数变多,从而延迟整个页面的交互就绪时间。
这里我们可以利用事件冒泡解决事件处理程序过多的问题。
上面的例子,我们可以将三个事务处理程序缩减为一个,示例如下:
window.onload = function () {
let list = document.getElementById('myTask')
list.addEventListener('click',function(event){
event = event || window.event
let target = event.target || event.srcElement
switch(target.id){
case 'task1':
// do something
break;
case 'task2':
// do somthing
break;
case 'task3':
// do somthing
break;
}
})
}
上面这段代码里,我们利用事件委托,只为<ul>元素添加了一个 onclick 事件处理程序。因为所有列表项都是<ul>元素的子节点,而且他们的事件会冒泡,所以点击事件最终会被<ul> 的 onclick事件处理。这样只取得了一个DOM 元素(list),只添加了一个事件处理程序,占用内存更少。