1. 需求描述--有啥用?
使用场景
当用户将鼠标放置在产品预览图上时,我们在预览图中以鼠标为中心,以 50 像素为半径划出部分区域并将该区域进行放大,将放大的图片展示在预览图旁边。当用户将鼠标在预览图上移动鼠标时,他可以改到对应区块的细节部分。
2. 需求分析--分析问题!
我们需要一个工具函数(或者hooks),这个工具函数(或者hooks)需要有以下几个功能:
【入参】
参数 | 含义 |
---|---|
target | DOM 节点或者 Ref 对象 |
options | 额外的配置项 |
options额外参数
参数 | 含义 | 类型 |
---|---|---|
onEnter | hover 时触发 | ( )=>{ } |
onLeave | 取消 hover 时触发 | ( )=>{ } |
onChange | onChange | ( )=>{ } |
【返回值】
参数 | 含义 | 类型 |
---|---|---|
isHovering | 鼠标元素是否处于 hover | boolean |
综上所述,梳理思路如下:
首先
我们要理解 hover 事件的本质其实就是鼠标进入事件和鼠标离开事件的语法糖!
其次
我们可以通过为传入的 dom 元素添加对应的事件处理函数达到我们的目的。
最后
当事件回调函数被触发时,执行对应的用户传入的函数后,还要更新鼠标元素是否处于 hover 的状态。
3. 手动实现--独立自主!
jsx
import React, { useEffect, useRef, useState } from 'react'
function useHover(...props) {
let [dom, options] = props
// 是否处于悬停状态
let [isHovering, setIsHovering] = useState(false)
// 悬停状态发生改变时,执行用户传入的函数
useEffect(() => {
options?.onChange()
}, [isHovering])
useEffect(() => {
if (!dom.current) return
// dom 节点存在时,为 dom 节点注册鼠标移入事件
dom.current.onmouseenter = () => {
setIsHovering(true)
options?.onEnter()
}
// dom 节点存在时,为 dom 节点注册鼠标移出事件
dom.current.onmouseleave = () => {
setIsHovering(false)
options?.onLeave()
}
}, [dom])
// 悬停状态作为 hooks 的返回值!
return isHovering
}
// 测试案例
export default () => {
let dom = useRef(null)
let isHovering = useHover(dom, {
onEnter: () => console.log('onEnter'),
onLeave: () => console.log('onLeave'),
onChange: () => console.log('onChange'),
})
return <>
<div ref={dom} style={{ width: '550px', height: '550px', backgroundColor: 'pink' }}>标题</div>
<span>{isHovering ? 'yse' : 'no'}</span>
</>
}