事件冒泡,捕获,委托
一、引言
JavaScript是一种广泛使用的脚本语言,用于为网页添加交互性。JavaScript的事件机制是实现用户交互的重要组成部分,它允许我们对用户的交互做出响应。在处理事件时,我们需要了解事件的传播方式以及如何使用事件委托来提高性能。
二、什么是事件捕获和事件冒泡
事件机制是指当特定的操作(如点击按钮、移动鼠标等)在DOM元素上发生时,会触发相应的事件。JavaScript通过监听事件并绑定对应的处理函数来响应用户的操作,对用户的交互做出响应。
在JavaScript中,事件是以事件流
的形式出现的,事件流顺序分为捕获和冒泡两种方式。 事件流分为三个阶段:1.捕获阶段 2.目标阶段 3.冒泡阶段。
事件捕获和事件冒泡是处理DOM事件的两种不同的机制。
三、事件捕获和冒泡的顺序
事件捕获的顺序是从最外层的元素开始,逐级向内部元素传播,直到达到目标元素
。 例如:window -> document -> html -> body -> div。
事件冒泡的顺序是从目标元素开始,逐级向外层元素传播,直到达到最外层的元素
。 例如:div -> body -> html -> document -> window。
四、addEventListener
在JavaScript中,我们可以使用addEventListener方法来绑定捕获和冒泡事件。
1 |
|
其中,event表示要绑定的事件类型,function表示事件触发时要执行的函数,useCapture是一个可选的参数,用于指定事件是使用捕获还是冒泡阶段进行处理。
当useCapture为false或未提供时,事件将在冒泡阶段进行处理;当useCapture为true时,事件将在捕获阶段进行处理。
1 |
|
当点击绿色方块时,输出greenBox、yellowBox、blueBox,因为绿色包含在黄色里,黄色和绿色被包含蓝色中。addEventListener不写第三个参数时,事件将在冒泡阶段进行处理,从目标元素开始,逐级向外层元素传播,直到达到最外层的元素,也就是绿色、黄色、蓝色。
同理,点击黄色时,输出yellowBox、blueBox。点击蓝色时,输出blueBox。
1 |
|
如上代码所示,将blueBox和greenBox的第三个参数设成true,点击绿色(greenBox),将输出blueBox、greenBox、yellowBox,因为blueBox和greenBox的事件将在捕获阶段进行处理,yellowBox的事件将在冒泡阶段进行处理。捕获的顺序是从最外层的元素开始,逐级向内部元素传播,直到达到目标元素,也就是蓝色、绿色,之后才是冒泡事件yellowBox。
如果将第三个参数全部设成true,点击绿色(greenBox),将输出blueBox、yellowBox、greenBox,因为事件将在捕获阶段进行处理,事件捕获的顺序是从最外层的元素开始,逐级向内部元素传播,直到达到目标元素,也就是蓝色、黄色、绿色。
五、阻止事件传播
1.event.stopPropagation()
调用该方法会阻止事件继续传播,但不会阻止其他事件处理程序被触发
。也就是说,如果一个元素上绑定了多个事件处理程序,调用该方法只会阻止事件传播到更高层级的元素,而不会阻止同一元素上的其他事件处理程序被触发。
1 |
|
在上面的示例中,当点击绿色方块时,调用event.stopPropagation()会阻止事件继续传播到外层元素,所以会阻止冒泡到黄色,而蓝色是在捕获阶段执行的,不会阻止,所以输出"blueBox和greenBox"
。
1 |
|
该方法不会阻止同一元素上的其他事件处理程序被触发,在上述代码中,输出结果是greenBox、greenBox222、greenBox333。
2.event.stopImmediatePropagation()
调用该方法会阻止事件继续传播,并且会阻止同一元素上的其他事件处理程序被触发
。也就是说,如果一个元素上绑定了多个事件处理程序,调用该方法会立即停止事件传播,并且不会触发同一元素上的其他事件处理程序。
1 |
|
在上面的示例中,当点击绿色方块(greenBox)时,调用event.stopImmediatePropagation()会阻止事件继续传播到外层元素,并且还会阻止自身的其他事件的触发,只会输出"greenBox"
,而不会输出其他内容。
六、事件委托
事件委托也称为事件代理(Event Delegation),事件委托是一种将事件处理程序绑定到一个父元素上,而不是将事件处理程序绑定到每个子元素上的技术。通过事件委托,可以减少事件处理程序的数量,提高性能和代码的可维护性。
示例代码
1 |
|
如上述代码所示,点击某一数字,就会输出对应内容。节点少的时候还好,如果节点多达上千上万个,就需要声明相当多的事件函数,比较消耗内存。而且如果列表经常发生动态变更,也会导致大量监听事件的移除和绑定。
在这种情况下,事件委托就可以体现它的优势了。
事件委托正是利用事件流的冒泡特性,将本来要绑定到多个元素的事件函数,委托到了其祖先元素上。
1 |
|
我们通过将事件处理程序绑定到父元素ul上,当点击列表项时,通过 event 对象拿到必要的信息,会打印出被点击的列表项的内容。如此这般,不管li有多少,更新多频繁,我们只需要维护一个函数就够了
。