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

React中MouseEnter与MouseLeave动画无法实现的问题求助

解决React Material-UI媒体卡片的平滑动画问题

嘿,别担心代码杂乱,新手摸索过程中有点混乱太正常啦!你的鼠标事件能正常触发,但动画没达到平滑效果,主要是缺少CSS过渡配置,还有几个小细节需要调整,咱们一步步来修复:

核心问题分析

  1. 没有添加过渡(transition)属性:状态变化时没有指定过渡时长和缓动逻辑,元素会瞬间切换状态,自然没有平滑动画。
  2. makeStyles无法响应组件内state变化:makeStyles的样式是在组件初始化时生成的,后续state更新不会重新计算这些样式,所以像scale: imgSize这种写法根本不会生效。
  3. 状态值的类型和写法错误:比如areaHeight初始是数字100,后来改成字符串'100%',单位不统一;textPosition里的!important完全没必要,React内联样式不需要这个语法。

修改后的完整代码

import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';

export default function SectionCard(props) {
  const [areaHeight, setAreaHeight] = useState('100px');
  const [imgScale, setImgScale] = useState(1);
  const [lineColor, setLineColor] = useState('dodgerblue');
  const [textPaddingTop, setTextPaddingTop] = useState(0);

  const useStyles = makeStyles((theme) => ({
    root: {
      maxWidth: 345,
      position: 'relative', // 给父元素加相对定位,确保遮罩层的绝对定位生效
      overflow: 'hidden', // 避免图片缩放时超出卡片容器
    },
    media: {
      height: 400,
      transition: 'transform 0.3s ease', // 图片缩放的过渡效果
    },
    greyCover: {
      backgroundColor: 'rgba(0, 0, 0, 0.5)',
      width: '100%',
      bottom: 0,
      position: 'absolute',
      transition: 'height 0.3s ease', // 遮罩层高度变化的过渡效果
    },
    line: {
      height: 5,
      width: '100%',
      borderRadius: 0,
      transition: 'background-color 0.3s ease', // 线条颜色变化的过渡效果
    },
    cardText: {
      fontFamily: 'Quicksand !important',
      color: 'white !important',
      transition: 'padding-top 0.3s ease', // 文本位置变化的过渡效果
    },
  }));

  const classes = useStyles();

  const handleMouseEnter = () => {
    setAreaHeight('100%');
    setLineColor('red');
    setImgScale(1.2);
    setTextPaddingTop(150);
  };

  const handleMouseLeave = () => {
    setAreaHeight('100px');
    setLineColor('dodgerblue');
    setImgScale(1);
    setTextPaddingTop(0);
  };

  return (
    <Grid item xs={12} sm={4}>
      <CardActionArea className={classes.root} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
        <CardMedia 
          className={classes.media} 
          image={props.img} 
          style={{ transform: `scale(${imgScale})` }} // 动态缩放用内联样式,响应state变化
        />
        <CardContent 
          className={classes.greyCover} 
          style={{ height: areaHeight }} // 动态高度用内联样式
        >
          <div className={classes.cardText} style={{ paddingTop: `${textPaddingTop}px` }}>
            <Typography gutterBottom variant="h5" component="h2" align="center">
              {props.title}
            </Typography>
            <Typography component="p" align="center">
              {props.text}
            </Typography>
          </div>
        </CardContent>
      </CardActionArea>
      <Paper className={classes.line} style={{ backgroundColor: lineColor }} /> {/* 动态颜色用内联样式 */}
    </Grid>
  );
}

关键修改点说明

  • 添加过渡效果:给所有需要动画的元素(遮罩、图片、线条、文本)都加上了transition属性,指定了0.3秒的过渡时长和自然的缓动函数,让状态变化更平滑。
  • 动态样式移至内联style:makeStyles生成的类是静态的,无法响应state更新,所以把图片缩放、遮罩高度、线条颜色这些动态样式放到元素的style属性里,确保状态变化时样式能实时更新。
  • 统一状态值类型:把areaHeight初始值改成'100px',和'100%'保持字符串类型,避免单位混乱导致的过渡异常。
  • 优化卡片容器:给root类添加overflow: hidden,避免图片缩放时超出卡片边界,视觉效果更整洁。
  • 拆分事件处理:把原来逗号分隔的setState拆成单独的函数调用,代码更清晰易维护。

现在你再试试,鼠标悬停时灰色遮罩会平滑展开到全屏,图片慢慢放大,线条颜色渐变,文本也能平滑上移到中部啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 10:18:16