You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

用framer-motion实现滚轮触发的类切换动画,修复返回无动画问题

问题修复与优化方案

现有代码问题分析

  1. 事件清理函数存在无效代码:window.removeEventListener("load", handleLoad)未定义handleLoad,会导致控制台报错。
  2. 布局模型切换冲突:isOpen状态切换时,从flex布局改为absolute定位,两种布局模型差异过大,导致Motion的layout无法追踪状态变化,返回右侧时无动画。
  3. 未实现垂直居中:内容容器缺少垂直居中的样式配置。

修复后完整代码

状态与滚轮监听部分

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>

关键修改说明

  1. 修复事件清理:移除无效的handleLoad监听代码,避免控制台报错。
  2. 统一布局模型:将两种状态下的布局统一为absolute定位,通过right和x属性控制位置,确保Motion的layout能正确追踪状态变化,实现双向动画。
  3. 垂直居中实现:内容容器通过top: 1/2和transform: translateY(-50%)实现垂直居中,同时保留旋转效果。
  4. 初始位置设置:通过right: "-calc(100% - 20px)"让内容初始时大部分在右侧外,仅露出20px宽度。
  5. 节流优化:给滚轮监听添加节流,避免一次滚动触发多次状态切换,提升交互体验。

内容的提问来源于stack exchange,提问作者bnvmnvbm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:37:10