File size: 999 Bytes
55847d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
26
27
28
29
30
31
32
33
import { useEffect, type RefObject } from 'react'

/**
 * 点击目标元素外部时触发 handler
 *
 * @param ref     需要检测的目标元素 ref
 * @param handler 点击外部时的回调
 * @param enabled 是否启用(默认 true)。可传入 showMenu 状态,菜单关闭时暂停监听以减少 document 事件开销
 *
 * 使用示例:
 * ```tsx
 * const menuRef = useRef<HTMLDivElement>(null)
 * const [open, setOpen] = useState(false)
 * useOutsideClick(menuRef, () => setOpen(false), open)
 * ```
 */
export function useOutsideClick<T extends HTMLElement>(
  ref: RefObject<T | null>,
  handler: () => void,
  enabled = true,
): void {
  useEffect(() => {
    if (!enabled) return
    const listener = (e: MouseEvent) => {
      if (ref.current && !ref.current.contains(e.target as Node)) {
        handler()
      }
    }
    document.addEventListener('mousedown', listener)
    return () => document.removeEventListener('mousedown', listener)
  }, [ref, handler, enabled])
}