Skip to content

🎧 useEventListener - 事件监听神器

🌟 介绍

想象一下,你的组件就像一个聪明的管家,能够在合适的时机自动监听各种事件,并在离开时优雅地清理干净。useEventListener 就是这样一个贴心的助手!

它会在组件 mountedactivated 时自动绑定事件,在 unmounteddeactivated 时自动解绑事件,让你告别手动管理事件监听器的烦恼。无论是窗口大小变化、鼠标点击,还是键盘按键,都能轻松搞定!

🚀 代码演示

基础用法 - 监听窗口事件

js
import { ref } from 'vue';
import { useEventListener } from '@vant/use';

export default {
  setup() {
    // 🪟 监听窗口大小变化
    useEventListener('resize', () => {
      console.log('窗口大小改变了!');
    });

    // 📱 监听设备方向变化
    useEventListener('orientationchange', () => {
      console.log('设备方向改变了!');
    });

    // ⌨️ 监听键盘事件
    useEventListener('keydown', (event) => {
      if (event.key === 'Escape') {
        console.log('用户按下了 ESC 键');
      }
    });
  },
};

指定目标元素 - 精准监听

js
import { ref, onMounted } from 'vue';
import { useEventListener } from '@vant/use';

export default {
  setup() {
    const buttonRef = ref();
    const containerRef = ref();

    onMounted(() => {
      // 🎯 监听特定按钮的点击
      useEventListener(
        'click',
        () => {
          console.log('按钮被点击了!');
        },
        { target: buttonRef }
      );

      // 📦 监听容器的滚动事件
      useEventListener(
        'scroll',
        (event) => {
          console.log('容器滚动位置:', event.target.scrollTop);
        },
        { target: containerRef }
      );
    });

    return {
      buttonRef,
      containerRef,
    };
  },
};

手动清理 - 灵活控制

js
import { ref } from 'vue';
import { useEventListener } from '@vant/use';

export default {
  setup() {
    const isListening = ref(true);

    // 🧹 获取清理函数
    const cleanup = useEventListener('resize', () => {
      console.log('窗口大小改变');
    });

    // 🎛️ 动态控制监听状态
    const toggleListener = () => {
      if (isListening.value) {
        cleanup(); // 停止监听
        isListening.value = false;
      } else {
        // 重新开始监听
        useEventListener('resize', () => {
          console.log('重新开始监听窗口变化');
        });
        isListening.value = true;
      }
    };

    return {
      isListening,
      toggleListener,
    };
  },
};

高级配置 - 性能优化

js
import { ref } from 'vue';
import { useEventListener } from '@vant/use';

export default {
  setup() {
    const scrollContainer = ref();

    // 🚀 使用 passive 模式优化滚动性能
    useEventListener(
      'scroll',
      (event) => {
        // 不会调用 preventDefault,性能更好
        console.log('滚动位置:', event.target.scrollTop);
      },
      {
        target: scrollContainer,
        passive: true, // 提升滚动性能
      }
    );

    // 🎯 使用捕获模式
    useEventListener(
      'click',
      (event) => {
        console.log('在捕获阶段处理点击事件');
      },
      {
        target: document.body,
        capture: true, // 在捕获阶段触发
      }
    );

    return {
      scrollContainer,
    };
  },
};

移动端适配 - 触摸事件

js
import { ref } from 'vue';
import { useEventListener } from '@vant/use';

export default {
  setup() {
    const touchArea = ref();
    const startPos = ref({ x: 0, y: 0 });

    // 👆 触摸开始
    useEventListener(
      'touchstart',
      (event) => {
        const touch = event.touches[0];
        startPos.value = {
          x: touch.clientX,
          y: touch.clientY,
        };
      },
      { target: touchArea, passive: true }
    );

    // 👆 触摸移动
    useEventListener(
      'touchmove',
      (event) => {
        const touch = event.touches[0];
        const deltaX = touch.clientX - startPos.value.x;
        const deltaY = touch.clientY - startPos.value.y;
        
        console.log('滑动距离:', { deltaX, deltaY });
      },
      { target: touchArea, passive: true }
    );

    return {
      touchArea,
    };
  },
};

📚 API 参考

类型定义

ts
type Options = {
  target?: EventTarget | Ref<EventTarget>;
  capture?: boolean;
  passive?: boolean;
};

function useEventListener(
  type: string,
  listener: EventListener,
  options?: Options,
): () => void;

参数说明

参数说明类型默认值
type🎯 监听的事件类型(如 'click', 'resize', 'scroll')string-
listener🎧 事件回调函数EventListener-
options⚙️ 可选的配置项Options-

Options 配置

参数说明类型默认值
target🎯 绑定事件的目标元素EventTarget | Ref<EventTarget>window
capture📥 是否在事件捕获阶段触发booleanfalse
passive🚀 设置为 true 时,表示 listener 永远不会调用 preventDefault,可提升性能booleanfalse

返回值

类型说明
() => void🧹 清理函数,调用后会移除事件监听器

🎯 实际应用场景

📱 移动端手势识别

js
// 实现左右滑动切换
const useSwipeGesture = (onSwipeLeft, onSwipeRight) => {
  let startX = 0;
  
  useEventListener('touchstart', (e) => {
    startX = e.touches[0].clientX;
  }, { passive: true });
  
  useEventListener('touchend', (e) => {
    const endX = e.changedTouches[0].clientX;
    const diff = startX - endX;
    
    if (Math.abs(diff) > 50) {
      diff > 0 ? onSwipeLeft() : onSwipeRight();
    }
  }, { passive: true });
};

🖥️ 响应式布局监听

js
// 监听屏幕尺寸变化,动态调整布局
const useResponsiveLayout = () => {
  const isMobile = ref(window.innerWidth < 768);
  
  useEventListener('resize', () => {
    isMobile.value = window.innerWidth < 768;
  });
  
  return { isMobile };
};

⌨️ 快捷键系统

js
// 实现全局快捷键
const useHotkeys = () => {
  useEventListener('keydown', (e) => {
    if (e.ctrlKey && e.key === 's') {
      e.preventDefault();
      console.log('保存快捷键触发');
    }
  });
};

💡 最佳实践

✅ 推荐做法

js
// 1. 使用 passive 优化滚动性能
useEventListener('scroll', handler, { passive: true });

// 2. 监听特定元素而非全局
useEventListener('click', handler, { target: buttonRef });

// 3. 在需要时手动清理
const cleanup = useEventListener('resize', handler);
// 在某个条件下清理
if (shouldCleanup) cleanup();

❌ 避免的用法

js
// ❌ 不要在事件处理器中执行耗时操作
useEventListener('scroll', () => {
  // 避免复杂计算
  heavyComputation();
});

// ❌ 不要忘记清理定时器等副作用
useEventListener('click', () => {
  setInterval(() => {
    // 可能导致内存泄漏
  }, 1000);
});

🛠️ 调试技巧

事件监听状态检查

js
// 添加调试信息
const cleanup = useEventListener('click', (e) => {
  console.log('事件触发:', {
    type: e.type,
    target: e.target,
    timestamp: Date.now(),
  });
});

// 检查是否正确清理
onUnmounted(() => {
  console.log('组件卸载,检查事件监听器是否已清理');
});

性能监控

js
// 监控事件频率
let eventCount = 0;
useEventListener('scroll', () => {
  eventCount++;
  if (eventCount % 100 === 0) {
    console.log(`滚动事件已触发 ${eventCount} 次`);
  }
}, { passive: true });

📚 相关文档

🎯 事件处理相关

📱 移动端相关

🎨 UI 交互相关

🛠️ 开发工具

📖 实战案例

基於Vant構建的企業級移動端解決方案