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

React中onMouseEnter事件异常:元素仅首次悬停时改变位置

解决React中悬停元素仅首次移动的问题

嘿,我完全懂你遇到的困扰——现在你的组件只会在第一次鼠标悬停时挪位置,之后就再也没反应了对吧?这主要有两个核心原因:

  1. 你只给hover状态绑定了一次固定位置的变化,没有持续生成新位置的逻辑;
  2. 当元素移走后,鼠标其实已经不在元素范围内了,onMouseEnter只会触发一次,后续不会再触发。

下面是修改后的完整方案,能让元素在鼠标悬停时持续随机移动,直到鼠标离开:

修改Hover组件

我们需要添加定时器来持续更新位置,同时管理位置状态:

import React, { Component } from 'react'

export class Hover extends Component {
  state = { 
    hovered: false,
    position: { left: '20rem', top: '9rem' } // 初始位置
  };
  moveInterval = null;

  // 生成随机位置的辅助函数,避免元素移出视口
  getRandomPosition = () => {
    const maxLeft = window.innerWidth - 300; // 300是元素大致宽度
    const maxTop = window.innerHeight - 100; // 100是元素大致高度
    return {
      left: `${Math.random() * maxLeft}px`,
      top: `${Math.random() * maxTop}px`
    };
  };

  componentDidUpdate(prevProps, prevState) {
    // 当hover状态变为true且无定时器时,启动定时移动
    if (this.state.hovered && !prevState.hovered) {
      this.moveInterval = setInterval(() => {
        this.setState({ position: this.getRandomPosition() });
      }, 300); // 每300毫秒移动一次,可根据需求调整速度
    }
    // 当hover状态变为false时,清除定时器并重置位置
    if (!this.state.hovered && prevState.hovered) {
      clearInterval(this.moveInterval);
      this.setState({ position: { left: '20rem', top: '9rem' } });
    }
  }

  componentWillUnmount() {
    // 组件卸载时清除定时器,防止内存泄漏
    if (this.moveInterval) {
      clearInterval(this.moveInterval);
    }
  }

  render() {
    return (
      <div className="app"
        onMouseEnter={() => this.setState({ hovered: true })}
        onMouseLeave={() => this.setState({ hovered: false })}
      >
        {this.props.children(this.state.hovered, this.state.position)}
      </div>
    );
  }
}

export default Hover

修改App.js

现在我们要使用动态位置,并给元素设置绝对定位,确保移动不影响布局:

import React from "react";
import "./styles.css";
import Hover from "./Hover";

export default function App() {
  return (
    <div className="app-container"> {/* 添加容器作为定位参考 */}
      <Hover>
        {(hovered, position) => (
          <h2 className="content"
            style={{
              backgroundColor: hovered ? "blue" : "yellow",
              position: 'absolute', // 开启绝对定位
              left: position.left,
              top: position.top,
              transition: 'all 0.3s ease' // 添加过渡动画,让移动更平滑
            }}
          >
            Move Your Cursor Closer
          </h2>
        )}
      </Hover>
    </div>
  );
}

修改styles.css

给容器设置相对定位,确保绝对定位的元素以它为参考:

.app-container{
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
.content{
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  text-decoration: none;
  font-size: 2rem;
  margin: 0; /* 去掉默认margin,避免位置偏差 */
}

关键修改点解释

  • 定时器管理:通过componentDidUpdate监听hover状态变化,启动/清除定时器,实现持续移动效果;
  • 随机位置生成:自定义函数生成视口内的随机位置,防止元素移出屏幕;
  • 绝对定位:让元素可以自由移动,不会干扰页面其他布局;
  • 过渡动画:添加transition属性让移动更流畅,提升用户体验;
  • 内存泄漏防护:组件卸载时清除定时器,避免潜在的内存问题。

这样修改后,当你鼠标悬停到元素上时,它就会持续随机移动,直到你把鼠标移开啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 19:22:39