监听页面元素外的点击是一个很常见的需求,多用于浮窗的隐藏。要实现这样一个功能其实要远比想象的简单。
export function useClickAway(
target:
| Element
| Ref<Element | undefined>
| Array<Element | Ref<Element | undefined>>,
listener: EventListener,
options: UseClickAwayOptions = {}
) {
if (!inBrowser) {
return;
}
const { eventName = 'click' } = options;
const onClick = (event: Event) => {
const targets = Array.isArray(target) ? target : [target];
const isClickAway = targets.every((item) => {
const element = unref(item);
return element && !element.contains(event.target as Node);
});
if (isClickAway) {
listener(event);
}
};
useEventListener(eventName, onClick, { target: document });
}
export type UseClickAwayOptions = {
eventName?: string;
};
export function useEventListener<K extends keyof DocumentEventMap>(
type: K,
listener: (event: DocumentEventMap[K]) => void,
options?: UseEventListenerOptions
): void;
首先确认参数 target 可以是单个的 Element 或者多个 Element 组成的数组。因为触发事件默认采取时间冒泡流,所以我们只需要对 document 进行监听,获取当前的 evt.target 并通过 Node.contains()
来判断当前点击的位置是否为目标元素 target 本身或者其子元素。这样就可以检测出点击操作是否触发在目标区域之外,若是的话再去触发添加的监听函数。