用framer-motion实现滚轮触发的类切换动画,修复返回无动画问题
问题修复与优化方案
现有代码问题分析
- 事件清理函数存在无效代码:
window.removeEventListener("load", handleLoad)未定义handleLoad,会导致控制台报错。 - 布局模型切换冲突:
isOpen状态切换时,从flex布局改为absolute定位,两种布局模型差异过大,导致Motion的layout无法追踪状态变化,返回右侧时无动画。 - 未实现垂直居中:内容容器缺少垂直居中的样式配置。
修复后完整代码
状态与滚轮监听部分
import { useState, useEffect } from 'react'; import { throttle } from 'lodash'; // 可选,用于节流优化 const [isOpen, setIsOpen] = useState(false); // 节流优化:避免滚轮一次滚动触发多次状态切换 const handleWheel = throttle((event: WheelEvent) => { if (event.deltaY > 0) { setIsOpen(true); } else { setIsOpen(false); } }, 300); useEffect(() => { window.addEventListener("wheel", handleWheel); return () => { window.removeEventListener("wheel", handleWheel); // 移除无效的handleLoad监听代码 }; }, []);
动画组件部分
import { motion } from 'framer-motion'; <motion.div className="relative h-screen overflow-hidden" > <motion.div layout transition={{ layout: { duration: 0.3 } // 延长动画时长,提升视觉流畅度 }} className="absolute h-screen w-fit" // 初始状态:右侧外仅露出20px initial={{ right: "-calc(100% - 20px)" }} // 根据isOpen状态切换位置 animate={{ right: isOpen ? "50%" : "-calc(100% - 20px)", x: isOpen ? "-50%" : 0 // 居中时通过x偏移实现水平居中 }} > {/* 内容容器:始终垂直居中 */} <div className="fixed top-1/2 z-10 text-center" style={{ transform: "translateY(-50%) rotate(-90deg)" }} > content </div> </motion.div> </motion.div>
关键修改说明
- 修复事件清理:移除无效的
handleLoad监听代码,避免控制台报错。 - 统一布局模型:将两种状态下的布局统一为
absolute定位,通过right和x属性控制位置,确保Motion的layout能正确追踪状态变化,实现双向动画。 - 垂直居中实现:内容容器通过
top: 1/2和transform: translateY(-50%)实现垂直居中,同时保留旋转效果。 - 初始位置设置:通过
right: "-calc(100% - 20px)"让内容初始时大部分在右侧外,仅露出20px宽度。 - 节流优化:给滚轮监听添加节流,避免一次滚动触发多次状态切换,提升交互体验。
内容的提问来源于stack exchange,提问作者bnvmnvbm
相关产品推荐
相关产品推荐

