面试题答案
一键面试1. React中事件冒泡和捕获的工作机制
- 事件冒泡:
- 当一个元素上的事件被触发时,该事件会从最内层的元素开始,逐渐向外层元素传播,就像气泡从水底向上浮出水面一样。例如在DOM结构中有一个
<div>
包裹着一个<button>
,当点击<button>
时,首先<button>
上绑定的点击事件会被触发,然后事件会依次向上传播到<div>
以及更外层的祖先元素,只要这些祖先元素上也绑定了相同类型的点击事件,都会被依次触发。 - 在React中,虽然合成事件的底层机制对开发者有所封装,但基本的冒泡逻辑依然存在。React会将多个不同浏览器的原生事件进行统一封装,当事件触发时,React会按照冒泡顺序依次执行绑定在不同层次组件上的事件处理函数。
- 当一个元素上的事件被触发时,该事件会从最内层的元素开始,逐渐向外层元素传播,就像气泡从水底向上浮出水面一样。例如在DOM结构中有一个
- 事件捕获:
- 事件捕获与冒泡相反,事件从最外层的祖先元素开始,向内层元素传播,直到到达实际触发事件的目标元素。还是以
<div>
包裹<button>
为例,当点击<button>
时,事件首先会从最外层的祖先元素开始,依次向内传播,最先触发最外层元素上绑定的事件处理函数,然后依次向内层元素传播,直到到达<button>
。 - 在React中,可以通过在
addEventListener
的第三个参数设置为true
来开启事件捕获,不过在React的合成事件系统中,通过useEffect
等方式模拟原生事件捕获时需要注意其与合成事件机制的结合使用。
- 事件捕获与冒泡相反,事件从最外层的祖先元素开始,向内层元素传播,直到到达实际触发事件的目标元素。还是以
2. 两者之间的主要区别
- 传播方向:事件冒泡是从目标元素向祖先元素传播;事件捕获是从祖先元素向目标元素传播。
- 执行顺序:在事件流的处理过程中,事件捕获阶段先于目标阶段,而目标阶段之后是事件冒泡阶段。在React合成事件中,如果同时存在捕获和冒泡的事件处理函数,捕获阶段的函数会先执行,然后才是目标元素上的事件处理函数,最后是冒泡阶段的函数。
- 默认绑定方式:在React中,合成事件默认使用事件冒泡机制,这样可以在父组件中方便地统一处理子组件的事件,而无需为每个子组件都单独绑定事件处理函数。
3. 场景举例
- 优先使用事件冒泡的场景:
- 表单验证:例如有一个包含多个输入框的表单,每个输入框都有自己的输入验证逻辑。同时,表单还有一个提交按钮,当点击提交按钮时,需要验证所有输入框是否都满足要求。可以在每个输入框上绑定
onChange
事件,并在父表单组件上也绑定一个onChange
事件。当输入框内容改变时,事件冒泡到表单组件,表单组件可以统一收集所有输入框的状态并进行整体验证。这样可以避免为每个输入框都单独编写提交验证的逻辑,使代码更加简洁和易于维护。 - 菜单点击处理:假设有一个多级菜单结构,每个菜单项都有点击事件。当点击某个菜单项时,除了执行该菜单项自身的逻辑外,可能还需要在父菜单级别进行一些状态更新,比如记录当前选中的菜单项层级等。通过事件冒泡,可以在父菜单组件中统一处理这些逻辑,而不需要为每个菜单项都单独绑定到顶层的处理函数。
- 表单验证:例如有一个包含多个输入框的表单,每个输入框都有自己的输入验证逻辑。同时,表单还有一个提交按钮,当点击提交按钮时,需要验证所有输入框是否都满足要求。可以在每个输入框上绑定
- 优先考虑事件捕获的场景:
- 页面点击遮罩层关闭:例如在一个弹出框组件中,弹出框有一个遮罩层,当点击遮罩层时需要关闭弹出框。同时,弹出框内部可能还有一些按钮等交互元素。如果使用事件冒泡,当点击弹出框内部按钮时,事件也会冒泡到遮罩层,导致弹出框意外关闭。此时使用事件捕获,在遮罩层上绑定点击事件捕获,只有当点击事件从外层向内传播到遮罩层时才会触发关闭逻辑,这样可以避免内部元素点击误触发遮罩层的关闭事件。
- 安全控制区域:假设页面中有一个安全控制区域,只有当用户在该区域内触发事件时才进行特定的权限验证等操作。可以在该区域的外层元素上绑定事件捕获,当事件从外层向内传播到该区域时,首先进行权限验证等操作,确保只有有权限的用户操作才会继续向内传播到实际的目标元素,从而提高安全性。