跳到主要内容

Vue3 的事件绑定原理

Vue 3 的事件绑定原理在底层主要依赖于浏览器原生的 addEventListener,这与 React 的合成事件(SyntheticEvent)机制是不同的。

🧬 Vue 3 事件绑定原理与实现

在 Vue 3 中,无论是原生 DOM 事件(如 clickinput)还是组件自定义事件,都是通过 v-on 指令(或其简写 @)来实现的。

其底层实现逻辑如下:

  1. 原生事件绑定v-on 用在普通的 HTML 元素上时,它会直接监听对应的原生 DOM 事件。Vue 3 在创建虚拟 DOM (VNode) 时,会将事件处理函数作为 props 的一部分进行传递。在元素挂载或更新时,Vue 内部的 patchProp 函数会处理这些事件 props,并最终调用原生的 addEventListener 来绑定事件。

  2. 事件修饰符的处理 Vue 3 提供了便捷的事件修饰符,如 .stop.prevent.once 等。在底层,Vue 并非简单地将所有事件都用同一个包装函数处理。对于 .once.capture.passive 这些修饰符,Vue 会直接将它们作为 addEventListener 的第三个参数 options 对象的属性,充分利用了浏览器原生的支持。而对于 .stop.prevent 等,则会生成一个包装函数,在触发用户定义的处理函数前先调用相应的方法(如 event.stopPropagation())。

  3. 组件事件v-on 用在自定义组件上时,它监听的是由该组件通过 this.$emit(在选项式 API 中)或 emit 函数(在组合式 API <script setup> 中)触发的自定义事件,而不是原生 DOM 事件。这实现了父子组件间的通信。

⚖️ 与 React 合成事件的对比

Vue 3 的事件机制并不等同于 React 的合成事件。

  • React 的合成事件 (SyntheticEvent) React 实现了一套自己的事件系统,称为“合成事件”。它采用 事件委托 (Event Delegation) 的机制,将绝大多数事件监听器统一代理到文档根节点(如 document)上。当事件触发时,React 会创建一个 SyntheticEvent 对象来包装原生事件,以抹平不同浏览器间的兼容性差异,并实现自己的事件流控制。

  • Vue 3 的原生事件 如前所述,Vue 3 默认情况下是直接在对应的 DOM 元素上使用 addEventListener 进行绑定,没有经过一层像 React 那样的统一事件系统。这使得 Vue 的事件处理更直观,与原生 HTML 事件模型保持高度一致,降低了学习成本。

✨ Vue Vapor 模式下的变化

值得注意的是,在 Vue 3.4+ 版本引入的 Vapor[ˈveɪpər] 模式(一种用于构建无虚拟 DOM 组件的编译模式)中,事件处理机制发生了改变。

在 Vapor 模式下,为了追求极致的性能和减少内存占用,事件绑定采用了与 React 类似的 事件委托 策略。它会将事件监听器代理到 document 上,通过一个全局的事件处理器来统一派发事件。但这属于特定模式下的优化,并非 Vue 3 默认行为。

总结一下:

特性ReactVue 3 (默认)Vue 3 (Vapor 模式)
底层机制合成事件 (SyntheticEvent)原生 addEventListener事件委托 (Event Delegation)
绑定方式事件委托到根节点直接绑定到元素事件委托到 document
浏览器兼容自身处理兼容性依赖浏览器原生支持依赖浏览器原生支持