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

Next.js结合Framer Motion用Router.push做页面切换动画二次点击失效问题

问题根因

你遇到的是Framer Motion共享布局动画在Next.js路由来回切换后的状态残留问题,核心原因有三个:

  1. 点击图片设置的isClicked状态在路由跳转后没有重置,返回首页时状态上下文冲突导致动画无法触发
  2. 列表渲染用index作为key,可能导致元素复用异常,破坏layoutId的对应关系
  3. 旧版本Framer Motion的AnimateSharedLayout没有随路由切换重置上下文,残留了之前的布局动画标识

修复方案

1. 跳转完成后重置点击状态

修改点击处理函数,利用router.push返回的Promise,等路由跳转完成后重置isClicked,避免状态残留:

const onHandlerClick = async (item, href, e) => {
    e.preventDefault();
    setIsClicked(item);
    await router.push(href, { scroll: false });
    // 路由跳转完成后重置状态,保证返回首页时状态干净
    setIsClicked(null);
};

2. 替换列表渲染的key

将遍历的key从数组下标替换为item本身,避免元素复用异常:

{images.map((item) => {
    return (
        <motion.div
            key={item} // 替换原有的index
            className="c-home-overflowimage c-home-overflowimage2"
            layoutId={`imageAnimation${item}`}
            variants={isClicked === item ? false : postVariants}
            transition={{ ...transition }}
        >
            {/* 其余内部代码不变 */}
        </motion.div>
    )
})}

3. 重置AnimateSharedLayout上下文(可选,针对旧版本Framer Motion)

给AnimateSharedLayout添加和页面组件一致的key,每次路由切换强制重置共享布局上下文:

<AnimateSharedLayout type="crossfade" key={router.asPath}>
    <AnimatePresence exitBeforeEnter initial={false}>
        <Component {...pageProps} key={router.asPath} />
    </AnimatePresence>
</AnimateSharedLayout>

如果使用的是Framer Motion v5及以上版本,AnimateSharedLayout已经被废弃,直接移除外层的AnimateSharedLayout包裹,仅保留AnimatePresence即可正常使用layoutId共享动画。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:57:02