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

按钮悬停气泡动画仅保存JSX文件后生效,刷新后失效求助

问题分析与解决方案

你这个问题核心是DOM元素获取时机错误:页面刷新时,document.querySelector代码在React组件还没完成渲染、按钮元素未挂载到DOM时就执行了,导致找不到元素,动画失效;而VS Code保存后是热重载,此时组件已经渲染完成,DOM元素存在,所以查询成功,动画正常。

解决步骤

  1. 使用React的Ref获取DOM元素,替代全局document.querySelector,这是React操作DOM的标准方式
  2. 在组件挂载完成后初始化HoverButton,通过useEffect钩子确保DOM渲染完毕再执行动画逻辑
  3. 添加事件清理逻辑,避免组件卸载后残留事件导致内存泄漏

修改后的完整代码

import './App.css';
import CoffeeSteamingBG from './CoffeeSteamingBG.jpg'
import Cart from './cart.svg'
import { gsap } from 'gsap';
import { useEffect, useRef } from 'react';

function App() {
  return (
    <>
      <FirstHeader />
      <IndexHome />
      <CoolBtns />
    </>
  )
}

function FirstHeader() {
  return (
    <header>
      <nav className='FirstNav'>
        <div className='OuterDivCJLogo'>
          <span className='FirstCJLogo'>Cuppa Java</span>
        </div>
      </nav>
    </header>
  )
}

function IndexHome() {
  return (
    <>
      <div className='slogan'>
        <h1><em>The Art of Coffee Elevated</em></h1>
      </div>
    </>
  )
}

function CoolBtns() {
  // 定义ref指向三个按钮
  const btn1Ref = useRef(null);
  const btn2Ref = useRef(null);
  const btn3Ref = useRef(null);
  // 保存HoverButton实例用于清理事件
  const hoverInstances = useRef([]);

  useEffect(() => {
    // 组件挂载后初始化动画
    const buttons = [btn1Ref.current, btn2Ref.current, btn3Ref.current];
    if (buttons.every(btn => btn)) {
      hoverInstances.current = buttons.map(btn => new HoverButton(btn));
    }

    // 组件卸载时清理事件监听
    return () => {
      hoverInstances.current.forEach(instance => instance.destroy());
    };
  }, []); // 空依赖确保只执行一次

  return (
    <div className='FunNew'>
      <ul className='Funul'>
        <li className='Funli'>
          <button ref={btn1Ref} className='FunBtn F1'><a>Menu</a></button>
        </li>
        <li className='Funli'>
          <button ref={btn2Ref} className='FunBtn F2'><a>Bistro</a></button>
        </li>
        <li className='Funli'>
          <button ref={btn3Ref} className='FunBtn F3'><a>Cart</a></button>
        </li>
      </ul>
    </div>
  )
}

class HoverButton {
  constructor(el) {
    this.el = el;
    this.hover = false;
    // 绑定this确保事件能正确移除
    this.onMouseMove = this.onMouseMove.bind(this);
    this.calculatePosition = this.calculatePosition.bind(this);
    this.calculatePosition();
    this.attachEventsListener();
  }
        
  attachEventsListener() {
    window.addEventListener('mousemove', this.onMouseMove);
    window.addEventListener('resize', this.calculatePosition);
  }

  // 添加销毁方法清理事件
  destroy() {
    window.removeEventListener('mousemove', this.onMouseMove);
    window.removeEventListener('resize', this.calculatePosition);
  }
        
  calculatePosition() {
     gsap.set(this.el, {
        x: 0,
        y: 0,
        scale: 1 });
      if(this.el) {
        const box = this.el.getBoundingClientRect();
        this.x = box.left + box.width * 0.5;
        this.y = box.top + box.height * 0.5;
        this.width = box.width;
        this.height = box.height;
      }
  }
        
  onMouseMove(e) {
    let hover = false;
    let hoverArea = this.hover ? 0.7 : 0.5;
    let x = e.clientX - this.x;
    let y = e.clientY - this.y;
    let distance = Math.sqrt(x * x + y * y);
    if (distance < this.width * hoverArea) {
      hover = true;
      if (!this.hover) {
        this.hover = true;
      }
      this.onHover(e.clientX, e.clientY);
    }
        
    if (!hover && this.hover) {
      this.onLeave();
      this.hover = false;
    }
  }
        
  onHover(x, y) {
    gsap.to(this.el, {
      x: (x - this.x) * 0.4,
      y: (y - this.y) * 0.4,
      scale: 1.15,
      ease: 'power2.out',
      duration: 0.4 });
        
    this.el.style.zIndex = 10;
  }
  onLeave() {
    gsap.to(this.el, {
      x: 0,
      y: 0,
      scale: 1,
      ease: 'elastic.out(1.2, 0.4)',
      duration: 0.7 });
        
    this.el.style.zIndex = 1;
  }
}

export default App

说明

修改后,React会先完成组件渲染并挂载DOM元素,再通过useEffect执行动画初始化,确保按钮元素存在;同时添加了事件清理逻辑,避免内存泄漏。页面刷新和热重载时动画都会正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 10:53:27