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

如何在ReactJS中实现动画?含动画文本与鼠标交互画布需求

React动画实现指南:从文本动画到鼠标交互画布

一、React中实现动画的核心方式

  • CSS原生动画:适合简单过渡、循环动画(如文本切换、hover效果),编写成本低,性能表现优秀。
  • React过渡组件:比如react-transition-group,专注处理组件挂载/卸载阶段的过渡动画。
  • 自定义Hook/脚本:针对复杂交互类动画(如鼠标跟随、画布绘制),需通过事件监听、状态更新实现精细化控制。

二、实用工具包推荐

不用从零搭建动画逻辑,这些工具包能大幅提升开发效率:

  • framer-motion:API简洁直观,支持声明式动画,内置手势、路径动画能力,新手友好。
  • react-spring:基于物理引擎的动画库,适合实现弹性、惯性等自然流畅的动效。
  • react-transition-group:React官方推荐的过渡组件库,聚焦组件生命周期的动画控制。

三、针对你的需求的具体实现

1. 动画文本(轮播切换效果)

你的代码中已有.animated-text容器,这里提供两种实现方案:

方案一:纯CSS动画

在Main.css中添加以下样式,无需修改JS代码:

.animated-text {
  height: 40px; /* 固定高度避免容器跳动 */
  overflow: hidden;
  position: relative;
}

.animated-text h3 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  opacity: 0;
  margin: 0;
  animation: textSlide 6s infinite;
}

.animated-text h3:nth-child(2) {
  animation-delay: 3s;
}

@keyframes textSlide {
  0%, 15% { opacity: 0; transform: translateY(20px); }
  20%, 50% { opacity: 1; transform: translateY(0); }
  55%, 100% { opacity: 0; transform: translateY(-20px); }
}

方案二:用framer-motion实现灵活可控的动画

先安装依赖:npm install framer-motion
再修改Main.js:

import React, { useState, useEffect } from 'react'
import Heading from '../organisms/Heading'
import Button from '../atoms/Button'
import { motion, AnimatePresence } from 'framer-motion'
import './Main.css'

const Main = () => {
  const [activeIndex, setActiveIndex] = useState(0)
  const texts = ["Web Designer", "Jr Full-stack Web Developer"]

  // 自动切换文本
  useEffect(() => {
    const timer = setInterval(() => {
      setActiveIndex(prev => (prev + 1) % texts.length)
    }, 3000)
    return () => clearInterval(timer)
  }, [texts.length])

  return (
    <div className='main_container'>
        <section className="main" id="main">
        <div className="content">
            <h2>Hello, I´m <br/> <span>Mateo Ghidini</span></h2>
            <div className="animated-text">
              <AnimatePresence mode="wait">
                <motion.h3
                  key={activeIndex}
                  initial={{ opacity: 0, y: 20 }}
                  animate={{ opacity: 1, y: 0 }}
                  exit={{ opacity: 0, y: -20 }}
                  transition={{ duration: 0.5 }}
                >
                  {texts[activeIndex]}
                </motion.h3>
              </AnimatePresence>
            </div>
            <Button className="btn" content="See My Work"/>
            <div className="media-icons">
                <a href="https://www.linkedin.com/in/mghidini/"><i className="fab fa-linkedin-in"></i></a>
                <a href="https://github.com/mateoghidini1998"><i className="fab fa-github"></i></a>
            </div>
        </div>
    </section>
    </div>
  )
}

export default Main 

2. 随鼠标移动变色的画布效果

通过自定义Hook监听鼠标位置,结合Canvas实现动态变色效果:

步骤1:创建自定义Hook useMousePosition.js

import { useState, useEffect } from 'react'

export const useMousePosition = () => {
  const [position, setPosition] = useState({ x: 0, y: 0 })

  useEffect(() => {
    const handleMouseMove = (e) => {
      setPosition({ x: e.clientX, y: e.clientY })
    }

    window.addEventListener('mousemove', handleMouseMove)
    return () => window.removeEventListener('mousemove', handleMouseMove)
  }, [])

  return position
}

步骤2:在Main.js中集成Hook与Canvas

import React, { useRef, useEffect } from 'react'
import Heading from '../organisms/Heading'
import Button from '../atoms/Button'
import { useMousePosition } from '../hooks/useMousePosition'
import './Main.css'

const Main = () => {
  const { x, y } = useMousePosition()
  const canvasRef = useRef(null)

  // 随鼠标位置更新画布颜色
  useEffect(() => {
    const canvas = canvasRef.current
    if (!canvas) return

    const ctx = canvas.getContext('2d')
    canvas.width = window.innerWidth
    canvas.height = window.innerHeight

    // 根据鼠标坐标计算RGB值
    const r = Math.floor((x / window.innerWidth) * 255)
    const g = Math.floor((y / window.innerHeight) * 255)
    const b = 150

    ctx.fillStyle = `rgb(${r}, ${g}, ${b})`
    ctx.fillRect(0, 0, canvas.width, canvas.height)
    // 添加半透明覆盖层,实现移动渐变效果
    ctx.fillStyle = 'rgba(255,255,255,0.05)'
    ctx.fillRect(0, 0, canvas.width, canvas.height)
  }, [x, y])

  return (
    <div className='main_container'>
        {/* 画布作为背景层 */}
        <canvas ref={canvasRef} className="mouse-canvas" />
        <section className="main" id="main">
        <div className="content">
            <h2>Hello, I´m <br/> <span>Mateo Ghidini</span></h2>
            <div className="animated-text">
                <h3>Web Designer</h3>
                <h3>Jr Full-stack Web Developer</h3>
            </div>
            <Button className="btn" content="See My Work"/>
            <div className="media-icons">
                <a href="https://www.linkedin.com/in/mghidini/"><i className="fab fa-linkedin-in"></i></a>
                <a href="https://github.com/mateoghidini1998"><i className="fab fa-github"></i></a>
            </div>
        </div>
    </section>
    </div>
  )
}

export default Main 

步骤3:在Main.css中设置画布样式

.mouse-canvas {
  position: fixed;
  top: 0;
  left: 0;
  z-index: -1; /* 置于内容下方 */
  pointer-events: none; /* 不干扰其他元素交互 */
}

.main_container {
  position: relative;
  min-height: 100vh;
}

四、关于自定义Hook的使用建议

如果是复用性高的逻辑(如鼠标位置监听、滚动状态监听),自定义Hook能让代码更简洁、可维护;如果只是单一页面的简单动画,直接写在组件内或用CSS实现即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 15:30:22