React vs Vue:點擊外部事件處理的對比與實現
在 Web 應用中,“點擊外部事件監聽”是一種常見需求,典型應用如:點擊彈窗外部關閉彈窗、點擊下拉菜單外關閉菜單。雖然在 React 和 Vue 中實現的原理類似——都是通過監聽 document
的點擊事件并判斷點擊是否在目標元素外,但在兩者框架中的編碼方式和理念卻有所不同。
📦 原理一致:判斷是否點擊在目標元素外
無論使用 Vue 還是 React,核心邏輯都是:
function isClickOutside(el: HTMLElement, target: EventTarget | null) {return el && target && !el.contains(target as Node)
}
這段邏輯判斷點擊的目標是否在 el
外部。
🔷 React 實現方式:使用 Hook
React 傾向于函數式和組合式思維,處理副作用的方式是通過 useEffect()
來注冊和銷毀事件。
import { useEffect, RefObject } from 'react'export function useClickOutside(ref: RefObject<HTMLElement>, handler: (e: MouseEvent) => void) {useEffect(() => {const listener = (e: MouseEvent) => {if (!ref.current || !isClickOutside(ref.current, e.target)) returnhandler(e)}document.addEventListener('mousedown', listener)return () => document.removeEventListener('mousedown', listener)}, [ref, handler])
}
使用方式:
const ref = useRef(null)
useClickOutside(ref, () => console.log('clicked outside'))
- ? 基于組件級 Hook
- ? 支持函數依賴管理
- ? 可按需組合并復用
🔶 Vue 實現方式:組合式 API + 自定義指令
Vue 提供兩種實現路徑:組合式 API(Composition API)和自定義指令(Directives)。
方法一:組合式 API
import { onMounted, onBeforeUnmount } from 'vue'export function useClickOutsideVue(elGetter: () => HTMLElement | null, handler: (e: MouseEvent) => void) {const listener = (e: MouseEvent) => {const el = elGetter()if (!el || !isClickOutside(el, e.target)) returnhandler(e)}onMounted(() => document.addEventListener('click', listener))onBeforeUnmount(() => document.removeEventListener('click', listener))
}
方法二:自定義指令
export const vClickOutside = {mounted(el: HTMLElement, binding: any) {el.__ClickOutside__ = (e: MouseEvent) => {if (isClickOutside(el, e.target)) {binding.value(e)}}document.addEventListener('click', el.__ClickOutside__)},unmounted(el: HTMLElement) {document.removeEventListener('click', el.__ClickOutside__)}
}
使用方式:
<template><div v-click-outside="onClose">彈窗</div>
</template>
- ? 更貼合模板語法
- ? 易于在 UI 層應用
- ? 可復用在多個 DOM 元素上
🔍 對比總結
對比項 | React | Vue |
---|---|---|
使用方式 | Hook(函數式組合) | Composition API / 指令 |
生命周期處理 | useEffect 管理副作用 | onMounted / onBeforeUnmount |
可讀性 | 適合開發者組織邏輯 | 更貼近模板,寫法語義直觀 |
復用性 | Hook 可組合 | 指令可復用在多個模板元素上 |
構建風格 | 以 JS 邏輯為中心 | 以模板交互為中心 |
? 最佳實踐建議
項目類型 | 推薦實現方式 |
---|---|
React 應用 | useClickOutside hook |
Vue3 + 組合式項目 | useClickOutsideVue hook |
Vue2 / 模板為主項目 | v-click-outside 指令 |
通過合理封裝點擊外部事件監聽邏輯,可以在保持代碼整潔的同時,提升組件交互體驗與可維護性。