useHover
一个鼠标悬停状态管理 Hook,提供简洁的 API 来检测元素的悬停状态。支持延迟触发、自定义事件和条件控制等高级功能。
基础用法
🎯 基础悬停检测
基础悬停
🖱️ 悬停我
悬停状态: 否
卡片悬停效果
交互式按钮
高级用法示例
⚡ 高级悬停功能
延迟悬停 (300ms)
🐌 慢慢悬停我 (300ms 延迟)
状态: 等待中...
条件悬停
🔧 条件悬停我
悬停计数器
📊
悬停次数: 0
悬停我增加计数
工具提示
API 参考
参数
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
options | UseHoverOptions | {} | 悬停检测配置选项,包含延迟、回调和启用控制等参数 |
UseHoverOptions
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
immediate | boolean | true | 是否立即启用检测,设为 false 可以手动控制何时开始监听 |
onEnter | (event: MouseEvent) => void | - | 鼠标进入时的回调函数,可用于执行额外的逻辑 |
onLeave | (event: MouseEvent) => void | - | 鼠标离开时的回调函数,可用于执行额外的逻辑 |
enterDelay | number | 0 | 进入延迟时间(毫秒),可避免快速移动时的误触发 |
leaveDelay | number | 0 | 离开延迟时间(毫秒),可避免鼠标在元素边缘移动时的状态抖动 |
返回值
useHover
返回一个包含目标元素引用、悬停状态和控制函数的数组:
typescript
const [targetRef, isHovered, setEnabled] = useHover(options);
索引 | 类型 | 说明 |
---|---|---|
0 | Ref<HTMLElement | null> | 目标元素的响应式引用,需绑定到要检测悬停状态的元素 |
1 | ComputedRef<boolean> | 悬停状态的只读响应式引用,表示当前元素是否处于悬停中 |
2 | (enabled: boolean) => void | 启用/禁用悬停检测的函数,可动态控制检测功能 |
类型定义
typescript
export type MouseEnterCallback = (event: MouseEvent) => void;
export type MouseLeaveCallback = (event: MouseEvent) => void;
export interface UseHoverOptions {
immediate?: boolean;
onEnter?: MouseEnterCallback;
onLeave?: MouseLeaveCallback;
enterDelay?: number;
leaveDelay?: number;
}
export type UseHoverReturn = [Ref<HTMLElement | null>, ComputedRef<boolean>, SetEnabledFunction];
export function useHover(options?: UseHoverOptions): UseHoverReturn;
使用场景
- 交互反馈 - 按钮、卡片、列表项等元素的悬停效果,提供视觉反馈
- 工具提示 - 实现悬停时显示的提示信息,增强用户体验
- 预览功能 - 悬停预览内容,如图片缩略图、文章摘要等
- 导航菜单 - 下拉菜单、级联菜单的显示控制,实现悬停展开
- 数据可视化 - 图表元素的高亮显示,突出显示数据点
- 图片画廊 - 悬停时显示图片控制按钮或额外信息
- 表格交互 - 悬停时高亮行或单元格,显示额外操作按钮
- 表单元素 - 为输入框、选择器等提供悬停状态样式
高级用法
延迟控制
通过设置延迟时间,避免用户快速移动鼠标时的频繁状态切换,提升用户体验:
typescript
// 进入延迟 300ms,离开延迟 100ms
const [elementRef, isHovered] = useHover({
enterDelay: 300, // 鼠标进入后等待 300ms 才触发悬停状态
leaveDelay: 100, // 鼠标离开后等待 100ms 才取消悬停状态
});
条件启用
根据特定条件动态启用或禁用悬停检测,适用于特定交互场景:
typescript
// 初始不启用悬停检测
const [elementRef, isHovered, setEnabled] = useHover({
immediate: false,
});
// 动态控制启用状态
const isEnabled = ref(true);
watch(isEnabled, (enabled) => {
setEnabled(enabled);
});
// 或者根据其他条件控制
watch(isEditing, (editing) => {
// 编辑模式下禁用悬停效果
setEnabled(!editing);
});
自定义回调函数
利用回调函数执行额外的逻辑,实现更复杂的交互效果:
typescript
const [elementRef, isHovered] = useHover({
onEnter: (event) => {
console.log("鼠标进入", event);
// 执行额外操作,如加载数据、播放动画等
loadPreviewData(elementId);
animateElement(event.target);
},
onLeave: (event) => {
console.log("鼠标离开", event);
// 执行清理操作
cancelPreviewLoading();
resetAnimation(event.target);
},
});
嵌套悬停检测
组合多个悬停检测实例,实现复杂的嵌套交互效果:
typescript
// 父元素悬停
const [parentRef, isParentHovered] = useHover();
// 子元素悬停
const [childRef, isChildHovered] = useHover();
// 组合悬停状态
const shouldShowDetails = computed(() => {
return isParentHovered.value || isChildHovered.value;
});
// 使用组合状态控制UI显示
watch(shouldShowDetails, (show) => {
if (show) {
showDetailPanel();
} else {
hideDetailPanel();
}
});
悬停统计与分析
结合其他逻辑,实现悬停行为的统计和分析:
typescript
// 悬停计数器
const hoverCount = ref(0);
const [counterRef, isHovered] = useHover({
onEnter: () => {
hoverCount.value++;
// 可以发送统计数据到分析系统
trackUserInteraction("hover", elementId);
},
});
// 悬停时长统计
const hoverStartTime = ref<number | null>(null);
const totalHoverTime = ref(0);
const [timerRef] = useHover({
onEnter: () => {
hoverStartTime.value = Date.now();
},
onLeave: () => {
if (hoverStartTime.value) {
const duration = Date.now() - hoverStartTime.value;
totalHoverTime.value += duration;
// 记录用户关注时长
trackEngagementTime(elementId, duration);
hoverStartTime.value = null;
}
},
});
动态样式与动画
结合计算属性,实现基于悬停状态的动态样式和动画效果:
typescript
const [imageRef, isImageHovered] = useHover();
// 动态样式对象
const imageStyle = computed(() => ({
transform: isImageHovered.value ? "scale(1.1)" : "scale(1)",
filter: isImageHovered.value ? "brightness(1.2)" : "brightness(1)",
boxShadow: isImageHovered.value ? "0 10px 20px rgba(0,0,0,0.2)" : "0 2px 5px rgba(0,0,0,0.1)",
transition: "all 0.3s ease",
}));
注意事项
- 自动清理 - 组件卸载时会自动清理事件监听器和定时器,避免内存泄漏
- 响应式控制 - 支持动态启用/禁用悬停检测,可根据应用状态灵活控制
- 延迟机制 - 使用延迟可以避免频繁的状态切换,提升用户体验
- 性能考虑 - 对于大量元素,考虑使用虚拟滚动或按需创建悬停实例
- 移动设备 - 在触摸设备上,悬停事件的行为不同,可能需要额外的触摸事件处理
- 嵌套元素 - 处理嵌套元素的悬停状态时,注意事件冒泡和捕获的影响
- 引用绑定 - 确保正确绑定元素引用,特别是在动态创建的元素上
- 类型安全 - 利用 TypeScript 类型定义,确保类型安全和代码提示
- 组合使用 - 可与其他 Hooks(如
useFocus
、useClickOutside
)组合使用,实现更复杂的交互 - SSR 兼容 - 在服务器端渲染环境中,确保只在客户端执行 DOM 操作