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

Next.js中Framer Motion移动端与桌面端初始动画适配问题求助

解决Next.js + Framer Motion 跨端动画初始状态错误问题

问题根源

你的自定义useMediaQuery初始状态设为false,而Next.js的SSR阶段无法访问window对象,无法获取真实的媒体查询结果;客户端组件挂载后,useEffect才会更新状态,但Framer Motion的初始动画在组件首次渲染时就已执行,导致用了错误的初始值触发动画。

解决方案

1. 修复useMediaQuery Hook,确保初始值正确

修改Hook,在客户端初始化时直接获取媒体查询结果,同时替换已废弃的addListener API:

import { useState, useEffect } from "react";

export default function useMediaQuery(query) {
  // 客户端初始化时直接获取匹配结果,SSR阶段返回默认值
  const [matches, setMatches] = useState(() => {
    if (typeof window !== "undefined") {
      return window.matchMedia(query).matches;
    }
    // SSR时可根据需求设置默认值,比如默认移动端
    return false;
  });

  useEffect(() => {
    const media = window.matchMedia(query);

    const updateMatches = () => {
      setMatches(media.matches);
    };

    // 监听媒体查询变化
    media.addEventListener("change", updateMatches);
    // 确保初始化值准确
    updateMatches();

    return () => media.removeEventListener("change", updateMatches);
  }, [query]);

  return matches;
}

2. 用动画控制器确保状态稳定后再启动动画

配合Framer Motion的useAnimation,等待useMediaQuery状态更新后再触发动画,避免初始值错误:

import { motion, useAnimation } from "framer-motion";
import useMediaQuery from "./useMediaQuery";

export default function WishCard() {
  // 修正变量名,避免逻辑混淆:isDesktop对应屏幕>=428px
  const isDesktop = useMediaQuery("(min-width: 428px)");
  const controls = useAnimation();

  // 状态稳定后启动动画
  useEffect(() => {
    controls.start("visible");
  }, [isDesktop, controls]);

  const wishCardVariant = {
    hidden: (isDesktop) => ({
      opacity: 0,
      y: isDesktop ? 0 : "100%", // 移动端从下方切入
      x: isDesktop ? "100%" : 0, // 桌面端从右侧切入
    }),
    visible: {
      opacity: 1,
      x: 0,
      y: 0,
      transition: { duration: 0.5 },
    },
  };

  return (
    <motion.div
      variants={wishCardVariant}
      initial="hidden"
      animate={controls}
      custom={isDesktop}
    >
      {/* 卡片内容 */}
    </motion.div>
  );
}

3. 额外优化:修正变量名避免逻辑混淆

原代码中onMobile变量对应min-width:428px的匹配结果,逻辑上是“是否为桌面端”,改成isDesktop能避免后续维护时的逻辑混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 08:15:38