侧边栏5秒未操作淡出,鼠标距20px时淡入功能实现问题
解决方案:实现侧边栏鼠标靠近20px触发淡入+超时淡出
问题梳理
- 预期效果:
- 超过5秒未操作(鼠标不在侧边栏20px范围内),侧边栏淡出至20%透明度
- 鼠标进入侧边栏20px范围内时,侧边栏立即淡入至100%透明度
- 当前问题:
- 仅能通过hover侧边栏触发淡入,无法实现“鼠标靠近20px”触发
- 鼠标离开侧边栏后保持100%透明度,未重新启动淡出计时器
修改后的代码实现
import { useState, useEffect, useRef } from 'react'; import classNames from 'classnames'; // 计算鼠标与元素的最短距离 const getDistanceToElement = (mouseX, mouseY, element) => { const rect = element.getBoundingClientRect(); // 计算鼠标在元素各方向的距离(超出元素范围为正,内部为0) const dx = Math.max(rect.left - mouseX, mouseX - rect.right, 0); const dy = Math.max(rect.top - mouseY, mouseY - rect.bottom, 0); // 勾股定理计算最短距离(鼠标在元素内时距离为0) return Math.sqrt(dx * dx + dy * dy); }; const Sidebar = () => { const [isSidebarFaded, setSidebarFaded] = useState(false); const [isMouseNearby, setIsMouseNearby] = useState(false); const sidebarRef = useRef(null); let fadeTimer = useRef(null); // 全局监听鼠标移动,判断是否在侧边栏20px范围内 useEffect(() => { const handleMouseMove = (e) => { if (!sidebarRef.current) return; const distance = getDistanceToElement(e.clientX, e.clientY, sidebarRef.current); const isNearby = distance <= 20; if (isNearby !== isMouseNearby) { setIsMouseNearby(isNearby); } }; document.addEventListener('mousemove', handleMouseMove); return () => { document.removeEventListener('mousemove', handleMouseMove); clearTimeout(fadeTimer.current); }; }, [isMouseNearby]); // 管理淡出计时器:鼠标不在附近时启动,进入附近时清除 useEffect(() => { if (!isMouseNearby) { // 5秒后触发淡出 fadeTimer.current = setTimeout(() => { setSidebarFaded(true); }, 5000); } else { // 鼠标靠近,立即淡入并清除计时器 clearTimeout(fadeTimer.current); setSidebarFaded(false); } return () => clearTimeout(fadeTimer.current); }, [isMouseNearby]); return ( <div ref={sidebarRef} className={classNames(styles.component, { [styles.fadeOut]: isSidebarFaded, })} > {/* 侧边栏内容 */} </div> ); }; export default Sidebar;
关键修改说明
- 距离计算逻辑:通过
getBoundingClientRect()获取侧边栏的位置信息,精准计算鼠标到元素的最短距离,判断是否在20px触发范围内。 - 全局鼠标监听:在document上监听
mousemove事件,替代原有的侧边栏局部hover监听,实现“靠近即触发”的效果。 - 计时器优化:
- 鼠标离开触发范围时,启动5秒计时器,到期后淡出侧边栏
- 鼠标进入范围时,立即清除计时器并将侧边栏淡入
- 用
useRef存储计时器ID,避免组件重渲染丢失引用
- 状态简化:用
isMouseNearby替代原isHovered状态,更准确反映“鼠标在附近”的触发条件
样式补充
确保添加过渡动画实现平滑的淡入淡出效果:
.component { transition: opacity 0.3s ease; opacity: 1; } .fadeOut { opacity: 0.2; }
内容的提问来源于stack exchange,提问作者hightides1973
相关产品推荐
相关产品推荐

