Vue如何编写自定义指令替代@mouseenter/@mouseleave监听hover状态
Vue自定义vHover指令实现方案
你最初的参考写法存在两个核心问题:
addEventListener的第二个参数必须传入函数引用,直接写赋值表达式会在指令挂载阶段就立刻执行,不会在鼠标事件触发时才运行- 硬编码固定的
state.hover变量会导致所有绑定指令的元素共享同一个状态,无法满足多元素独立绑定hover状态的复用需求
完整可复用实现
实现时需要额外注意:事件监听要在组件/元素卸载时主动移除,避免内存泄漏;同时要兼容Vue的ref响应式变量赋值逻辑。
const vHover = { mounted(el, binding) { // 将事件回调挂载到DOM节点上,方便卸载时精准移除 el.__hoverEnter = () => { const target = binding.value // 兼容传入ref的场景,自动更新.value if (target && typeof target === 'object' && 'value' in target) { target.value = true } } el.__hoverLeave = () => { const target = binding.value if (target && typeof target === 'object' && 'value' in target) { target.value = false } } // 绑定原生鼠标事件 el.addEventListener('mouseenter', el.__hoverEnter) el.addEventListener('mouseleave', el.__hoverLeave) }, unmounted(el) { // 移除事件监听,清理引用 el.removeEventListener('mouseenter', el.__hoverEnter) el.removeEventListener('mouseleave', el.__hoverLeave) delete el.__hoverEnter delete el.__hoverLeave } }
使用方式
全局注册该指令后,直接在模板里给对应元素绑定,传入要关联的ref响应式变量即可,无需手写重复的@mouseenter/@mouseleave逻辑:
<template> <!-- 给卡片绑定hover状态 --> <div class="card" v-hover="isCardHover"> 卡片内容 </div> <!-- 给按钮绑定独立的hover状态 --> <button v-hover="isBtnHover">操作按钮</button> </template> <script setup> import { ref } from 'vue' const isCardHover = ref(false) const isBtnHover = ref(false) </script>
补充说明
- 原生
mouseenter/mouseleave事件默认不会冒泡,刚好符合常规hover交互的触发预期,不会出现子元素触发父元素hover状态异常的问题 - 如果是Vue2项目,只需要把钩子名
mounted换成bind、unmounted换成unbind,核心逻辑无需修改 - 如果需要支持传入对象属性、getter/setter等更复杂的绑定场景,可以自行扩展
binding.value的判断逻辑
内容的提问来源于stack exchange,提问作者Artur Müller Romanov
相关产品推荐
相关产品推荐

