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

使用Framer Motion实现的自定义动画光标莫名消失问题求助

自定义Framer Motion光标在Next.js中几分钟后消失的解决方案

我用Next.js + TailwindCSS + Framer Motion搭建作品集网站,基于Framer Motion实现了自定义动画光标,初始运行正常,但页面重载几分钟后光标会莫名消失。降级Framer Motion至v5.3.2可解决该问题,但该版本与React 18存在兼容Bug,无法使用,且无法稳定复现此Bug。

相关代码与配置

自定义光标组件代码

<motion.div
  variants={variants}
  animate={cursorContext?.cursorVariant}
  className={`h-5 w-5 rounded-full fixed top-[50vh] left-[50vw] pointer-events-none z-[999] mix-blend-difference ${showCursor ? 'block' : 'hidden'}`}
/>

动画变体配置

const variants = {
    regular: {
      x: cursorContext!.mousePosition.x - 5,
      y: cursorContext!.mousePosition.y - 5,
      border: "white 2px solid",
    },

    clickable: {
      x: cursorContext!.mousePosition.x - 5,
      y: cursorContext!.mousePosition.y - 5,
      border: 'none',
      backgroundColor: 'white',
      width: 10,
      height: 10,
    },

    largeClickable: {
      x: cursorContext!.mousePosition.x - 10,
      y: cursorContext!.mousePosition.y - 10,
      border: 'none',
      backgroundColor: 'white',
      width: 20,
      height: 20,
    },
};

项目依赖配置

{
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "latest",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "devDependencies": {
    "@types/node": "18.11.3",
    "@types/react": "18.0.21",
    "@types/react-dom": "18.0.6",
    "@types/react-scroll": "^1.8.5",
    "autoprefixer": "^10.4.12",
    "framer-motion": "^7.6.15",
    "postcss": "^8.4.18",
    "react-icons": "^4.6.0",
    "react-scroll": "^1.8.8",
    "tailwindcss": "^3.2.1",
    "typescript": "4.8.4"
  }
}

可能的解决方案

1. 拆分变体中的状态引用与样式

当前变体直接从cursorContext读取mousePosition,可能导致动画实例在状态更新时出现引用失效或内存泄漏。建议将位置计算移到组件内,变体只保留纯样式:

import { useState, useEffect } from 'react';
import { motion } from 'framer-motion';

// 组件内计算位置
const [position, setPosition] = useState({ x: 0, y: 0 });

useEffect(() => {
  if (!cursorContext) return;
  
  const offset = cursorContext.cursorVariant === 'largeClickable' ? 10 : 5;
  setPosition({
    x: cursorContext.mousePosition.x - offset,
    y: cursorContext.mousePosition.y - offset,
  });
}, [cursorContext]);

// 纯样式变体
const variants = {
  regular: { border: "white 2px solid" },
  clickable: { border: 'none', backgroundColor: 'white', width: 10, height: 10 },
  largeClickable: { border: 'none', backgroundColor: 'white', width: 20, height: 20 },
};

// 组件渲染
<motion.div
  animate={{ ...position, ...variants[cursorContext?.cursorVariant || 'regular'] }}
  className={`h-5 w-5 rounded-full fixed top-[50vh] left-[50vw] pointer-events-none z-[999] mix-blend-difference ${showCursor ? 'block' : 'hidden'}`}
/>

2. 升级Framer Motion到最新稳定版

v7.6.15存在React 18下的潜在兼容问题,后续版本可能已修复动画实例回收的Bug,执行命令升级:

npm install framer-motion@latest

3. 排查showCursor状态异常

检查控制showCursor的逻辑是否存在误触发的情况,添加日志追踪状态变化:

useEffect(() => {
  console.log('showCursor状态变更:', showCursor);
}, [showCursor]);

4. 手动控制动画实例

使用useAnimation钩子手动管理动画,避免自动动画的潜在冲突:

import { useAnimation } from 'framer-motion';

const controls = useAnimation();

useEffect(() => {
  if (!cursorContext) return;
  
  const variant = variants[cursorContext.cursorVariant || 'regular'];
  const offset = cursorContext.cursorVariant === 'largeClickable' ? 10 : 5;
  
  controls.start({
    x: cursorContext.mousePosition.x - offset,
    y: cursorContext.mousePosition.y - offset,
    ...variant,
  });
}, [cursorContext, controls]);

<motion.div
  animate={controls}
  className={`h-5 w-5 rounded-full fixed top-[50vh] left-[50vw] pointer-events-none z-[999] mix-blend-difference ${showCursor ? 'block' : 'hidden'}`}
/>

5. 临时关闭React Strict Mode测试

React 18的Strict Mode会双重渲染组件,可能导致Framer Motion动画实例冲突。在_app.tsx中移除<React.StrictMode>包裹,测试是否解决问题:

// _app.tsx
export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 08:15:32