|
import type { Directive, DirectiveBinding } from 'vue' |
|
|
|
const CTX_CLICK_OUTSIDE_HANDLER = 'CTX_CLICK_OUTSIDE_HANDLER' |
|
|
|
interface CustomHTMLElement extends HTMLElement { |
|
[CTX_CLICK_OUTSIDE_HANDLER]?: (event: MouseEvent) => void |
|
} |
|
|
|
const clickListener = (el: HTMLElement, event: MouseEvent, binding: DirectiveBinding) => { |
|
const handler = binding.value |
|
|
|
const path = event.composedPath() |
|
const isClickOutside = path ? path.indexOf(el) < 0 : !el.contains(event.target as HTMLElement) |
|
|
|
if (!isClickOutside) return |
|
handler(event) |
|
} |
|
|
|
const ClickOutsideDirective: Directive = { |
|
mounted(el: CustomHTMLElement, binding) { |
|
el[CTX_CLICK_OUTSIDE_HANDLER] = (event: MouseEvent) => clickListener(el, event, binding) |
|
setTimeout(() => { |
|
document.addEventListener('click', el[CTX_CLICK_OUTSIDE_HANDLER]!) |
|
}, 0) |
|
}, |
|
|
|
unmounted(el: CustomHTMLElement) { |
|
if (el[CTX_CLICK_OUTSIDE_HANDLER]) { |
|
document.removeEventListener('click', el[CTX_CLICK_OUTSIDE_HANDLER]) |
|
delete el[CTX_CLICK_OUTSIDE_HANDLER] |
|
} |
|
}, |
|
} |
|
|
|
export default ClickOutsideDirective |