手写VueUse的onClickOutside函数

以下是手写 VueUse 的 onClickOutside 函数的实现,采用 Vue 3 组合式 API 风格,包含详细注释和代码:

typescript 复制代码
import { Ref, onMounted, onUnmounted } from 'vue';

/**
 * 检测点击目标元素外部的操作
 * @param targetRef 要监听的目标元素引用
 * @param callback 点击外部时触发的回调函数
 */
export function onClickOutside(
  targetRef: Ref<HTMLElement | null>,
  callback: (event: MouseEvent) => void
) {
  // 事件处理函数
  const listener = (event: MouseEvent) => {
    const target = targetRef.value;
    
    // 确保目标元素存在且事件目标存在
    if (!target || !event.target) return;

    // 判断点击是否发生在目标元素外部
    if (!target.contains(event.target as Node)) {
      callback(event);
    }
  };

  // 组件挂载时添加监听
  onMounted(() => {
    // 使用捕获阶段确保在阻止冒泡的情况下仍能触发
    document.addEventListener('click', listener, { capture: true });
  });

  // 组件卸载时移除监听
  onUnmounted(() => {
    document.removeEventListener('click', listener, { capture: true });
  });
}

使用示例

vue 复制代码
<script setup lang="ts">
import { ref } from 'vue';
import { onClickOutside } from './onClickOutside';

const target = ref<HTMLElement | null>(null);
const isOpen = ref(true);

onClickOutside(target, () => {
  isOpen.value = false;
});
</script>

<template>
  <div v-if="isOpen" ref="target" class="modal">
    点击外部区域关闭我
  </div>
</template>

实现要点解析

  1. 事件阶段处理

    • 使用 { capture: true } 在捕获阶段监听事件,确保即使其他事件调用了 stopPropagation() 也能触发
  2. 类型安全

    • 使用 TypeScript 类型标注,明确处理 HTMLElement 和事件对象类型
  3. 内存管理

    • 通过 onUnmounted 自动清理事件监听,避免内存泄漏
  4. 边界情况处理

    • 检查目标元素是否存在(targetRef.value
    • 检查事件目标是否存在(event.target
  5. DOM 判断逻辑

    • 使用 contains() 方法判断点击目标是否在监听元素内部

扩展功能建议

如需实现更复杂的功能,可以考虑添加以下特性:

  1. 排除元素:允许配置不触发回调的排除元素
  2. 事件类型 :支持监听其他事件类型(如 mousedown
  3. 响应式配置:通过响应式参数控制监听行为
  4. 立即触发:添加 immediate 选项支持初始状态检测
  5. 条件判断:添加执行回调的条件判断函数
相关推荐
恋猫de小郭23 分钟前
对于普通程序员来说 AI 是什么?AI 究竟用的是什么?
前端·flutter·ai编程
大怪v42 分钟前
前端:人工智能?我也会啊!来个花活,😎😎😎“自动驾驶”整起!
前端·javascript·算法
我是天龙_绍43 分钟前
vue3 props 如何写ts,进行类型标注
前端
叫我詹躲躲1 小时前
n8n 自动化工作流平台完整部署
前端·langchain·领域驱动设计
遂心_3 小时前
为什么 '1'.toString() 可以调用?深入理解 JavaScript 包装对象机制
前端·javascript
IT_陈寒3 小时前
JavaScript 性能优化:5 个被低估的 V8 引擎技巧让你的代码快 200%
前端·人工智能·后端
岛风风3 小时前
关于手机的设备信息
前端
ReturnTrue8683 小时前
nginx性能优化之Gzip
前端
w_y_fan4 小时前
Flutter 滚动组件总结
前端·flutter
wuli金居哇4 小时前
我用 Turborepo 搭了个 Monorepo 脚手架,开发体验直接起飞!
前端