use-hover-toggle.ts 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import type { Arrayable, MaybeElementRef } from '@vueuse/core';
  2. import type { Ref } from 'vue';
  3. import { computed, onUnmounted, ref, unref, watch } from 'vue';
  4. import { isFunction } from '@vben/utils';
  5. import { useElementHover } from '@vueuse/core';
  6. /**
  7. * 监测鼠标是否在元素内部,如果在元素内部则返回 true,否则返回 false
  8. * @param refElement 所有需要检测的元素。如果提供了一个数组,那么鼠标在任何一个元素内部都会返回 true
  9. * @param delay 延迟更新状态的时间
  10. * @returns 返回一个数组,第一个元素是一个 ref,表示鼠标是否在元素内部,第二个元素是一个控制器,可以通过 enable 和 disable 方法来控制监听器的启用和禁用
  11. */
  12. export function useHoverToggle(
  13. refElement: Arrayable<MaybeElementRef>,
  14. delay: (() => number) | number = 500,
  15. ) {
  16. const isHovers: Array<Ref<boolean>> = [];
  17. const value = ref(false);
  18. const timer = ref<ReturnType<typeof setTimeout> | undefined>();
  19. const refs = Array.isArray(refElement) ? refElement : [refElement];
  20. refs.forEach((refEle) => {
  21. const eleRef = computed(() => {
  22. const ele = unref(refEle);
  23. return ele instanceof Element ? ele : (ele?.$el as Element);
  24. });
  25. const isHover = useElementHover(eleRef);
  26. isHovers.push(isHover);
  27. });
  28. const isOutsideAll = computed(() => isHovers.every((v) => !v.value));
  29. function setValueDelay(val: boolean) {
  30. timer.value && clearTimeout(timer.value);
  31. timer.value = setTimeout(
  32. () => {
  33. value.value = val;
  34. timer.value = undefined;
  35. },
  36. isFunction(delay) ? delay() : delay,
  37. );
  38. }
  39. const watcher = watch(
  40. isOutsideAll,
  41. (val) => {
  42. setValueDelay(!val);
  43. },
  44. { immediate: true },
  45. );
  46. const controller = {
  47. enable() {
  48. watcher.resume();
  49. },
  50. disable() {
  51. watcher.pause();
  52. },
  53. };
  54. onUnmounted(() => {
  55. timer.value && clearTimeout(timer.value);
  56. });
  57. return [value, controller] as [typeof value, typeof controller];
  58. }