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

Next.js路由模态框使用Framer Motion时关闭动画不生效

问题原因

Framer Motion 退出动画失效是用法错误导致的,核心问题有两个:

  1. AnimatePresence 必须直接包裹被条件渲染控制显隐的 motion 元素才能检测到卸载时机、触发退出动画。你把组件套在_app.js最外层,和Modal内部的条件渲染节点隔了多层组件树,根本无法接管子元素的卸载流程。
  2. 你把遮罩层、模态框内容拆成了两个独立的条件渲染块,当路由变化isOpen变为false时,React会立刻将对应节点从DOM中移除,没有预留动画执行的时间。
修复步骤
  1. 删除_app.js外层包裹的全局AnimatePresence,全局包裹对组件内部的局部条件渲染动效无效,还会增加无意义的性能消耗。
  2. 在Modal组件内部直接引入AnimatePresence,包裹所有需要做进出动画的元素,让它直接接管条件渲染节点的挂载/卸载流程。
  3. 合并遮罩层、模态框内容的条件判断逻辑,给遮罩层也加上对应的淡入淡出动画,避免关闭时遮罩瞬间消失。
修正后的Modal组件代码
import { motion, AnimatePresence } from "framer-motion";
import Link from "next/link";
import { Box } from "@chakra-ui/react";

const Modal = ({ isOpen, place }) => {
  return (
    <AnimatePresence>
      {isOpen && (
        <>
          {/* 点击关闭的遮罩层 */}
          <Link href="/" scroll={false} passHref>
            <Box
              as={motion.div}
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.5, ease: "easeInOut" }}
              position="fixed"
              inset="0"
              width="100vw"
              height="100vh"
              bg="rgba(0,0,0,0.4)"
              zIndex={10}
            />
          </Link>
          {/* 模态框内容主体 */}
          <Box
            as={motion.div}
            initial={{ y: "50%", opacity: 0 }}
            animate={{ y: "0%", opacity: 1 }}
            exit={{ y: "50%", opacity: 0 }}
            transition={{ duration: 0.5, ease: "easeInOut" }}
            position="fixed"
            left="50%"
            top="50%"
            transform="translate(-50%, -50%)"
            zIndex={20}
            w="90%"
            maxW="600px"
            bg="white"
            borderRadius="lg"
            p={6}
          >
            {/* 这里放place对应的详情内容 */}
            {place}
          </Box>
        </>
      )}
    </AnimatePresence>
  );
};
补充说明

如果遇到路由跳转速度快于动画导致动画被提前截断的问题,可以把遮罩层的Link跳转改成 onClick 事件控制:先手动触发退出状态,等动画执行完成后再调用router.push('/')修改路由。常规场景下上面的写法已经可以正常触发0.5s的关闭动画,不需要额外处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:18:15