實務上要實作 Click Outside,多半都是將監聽器綁在 window 上,或是透過 Event 事件的 ComposePath() 方法來進行過濾,進而了解究竟有沒有點選該元素。
內容
1. 自行撰寫
用 ref 取得 DOM,然後撰寫 func 給 window 上的 ‘click’ 綁定。
邏輯
A. 點擊的 e.target 和你的目標元素比對
B. 若目標元素沒有包含 e.target,那就執行你所指定的函式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import { onMounted, onBeforeUnmount, Ref } from 'vue' const handleClickOutSide = (elRef: Ref<HTMLElement | null>, onClickOutside: () => void) => { if (!elRef) return const handler = (e: MouseEvent) => { const el = elRef.value if (!el) return if (!el.contains(e.target as Node)) { if (typeof onClickOutside === 'function') { onClickOutside() } } } onMounted(() => { window.addEventListener('click', handler) }) onBeforeUnmount(() => { window.removeEventListener('click', handler) }) } export default handleClickOutSide |
2. 使用 VueUse 的 onClickOutside
原理是透過 Event.composedPath()。它會回傳冒泡過程中所經過的所有 DOM 元素。
https://vueuse.org/core/onClickOutside/
誤區
無論你採用何種方法,都是在 window 上進行全域監聽。若你將此用於元件開發時,需要確保你不會因此產生多個監聽器。
舉例:若你用於開發一個 <Input> 元件的話,在你產生多個 input 時,便會觸發多個 clickOutside。因此, clickOutside 適合用於「僅會產生單一個元件」的場景。像是全部畫面的 Dialog 彈窗。
參考資料
1. 使用 vue 3 製作 click outside composables (組合式函數)
2. Event: composedPath() method
3. Vue3 – onClickOutside