关键词:事件冒泡和目标元素。
科普:
一个事件触发后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。
事件冒泡: 当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有的祖先元素中被触发。这个事件从事件的原始元素开始一直冒泡到DOM树最上层。
目标元素:任何事件的目标元素都是最开始的那个元素,在老IE下,目标元素是window.event.srcElement,其他浏览器event.target。
使用:
把事件处理器添加到一个父级元素上,等待一个事件从它的子级里冒泡上来,并且可以得知这个事件是从哪个元素开始的。
优点:
可以大量节省内存占用,减少事件注册;
在DOM更新后无需重新绑定事件处理器。
缺点:
事件冒泡的过程也需要耗时,越靠近顶层,事件的”事件传播链”越长,也就越耗时;
不是所有的事件都是能冒泡的,如blur、focus、load和unload。也不是所有事件都适合用事件代理的,如mousemove事件触发非常频繁会导致性能瓶颈,mouseout怪异的表现很难用事件代理来管理;
从浏览器的角度,相当于将父元素标记了一个非快速滚动区域,浏览器合成线程中将注册了事件浏览器的区域标记为非快速滚动区域。当用户事件发生在这些区域时,合成线程会将输入事件发送给主线程来处理。如果输入事件不是发生在非快速滚动区域,合成线程就无需主线程的参与来合成一个新的帧。输入事件代表着来自于用户的任何手势动作,所以用户滚动页面、触碰屏幕以及鼠标移动等操作都是输入事件。当用户的输入事件不是需要主线程处理的,比如在非快速滚动区域做了一个滚动的操作,合成线程每次都会告知主线程并且等主线程处理完才开始干活,用户体验流畅度会有影响。为了减轻这种情况的发生,可以为事件监听器传递pass: true选项。这个选项会告诉浏览器仍要在主线程中监听事件,合成线程页可以继续合成新的帧。