监听页面元素外的点击是一个很常见的需求,多用于浮窗的隐藏。要实现这样一个功能其实要远比想象的简单。

    1. export function useClickAway(
    2. target:
    3. | Element
    4. | Ref<Element | undefined>
    5. | Array<Element | Ref<Element | undefined>>,
    6. listener: EventListener,
    7. options: UseClickAwayOptions = {}
    8. ) {
    9. if (!inBrowser) {
    10. return;
    11. }
    12. const { eventName = 'click' } = options;
    13. const onClick = (event: Event) => {
    14. const targets = Array.isArray(target) ? target : [target];
    15. const isClickAway = targets.every((item) => {
    16. const element = unref(item);
    17. return element && !element.contains(event.target as Node);
    18. });
    19. if (isClickAway) {
    20. listener(event);
    21. }
    22. };
    23. useEventListener(eventName, onClick, { target: document });
    24. }
    25. export type UseClickAwayOptions = {
    26. eventName?: string;
    27. };
    28. export function useEventListener<K extends keyof DocumentEventMap>(
    29. type: K,
    30. listener: (event: DocumentEventMap[K]) => void,
    31. options?: UseEventListenerOptions
    32. ): void;

    首先确认参数 target 可以是单个的 Element 或者多个 Element 组成的数组。因为触发事件默认采取时间冒泡流,所以我们只需要对 document 进行监听,获取当前的 evt.target 并通过 Node.contains() 来判断当前点击的位置是否为目标元素 target 本身或者其子元素。这样就可以检测出点击操作是否触发在目标区域之外,若是的话再去触发添加的监听函数。