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

NextJS项目中NextUI卡片动画失效问题求助

解决NextUI卡片过渡动画不生效的问题

问题根源

你猜的没错——直接用{expandedCard !== null ? <ExpandedCard /> : <卡片网格/>}这种条件渲染时,React会完全卸载旧组件、挂载新组件,被卸载的元素直接从DOM中消失,CSS过渡没有可作用的元素,自然不会生效。

解决方案:保留DOM元素,用状态控制样式过渡

核心思路是让卡片网格和展开卡片同时存在于DOM中,通过React状态控制它们的透明度、可见性等样式属性,让CSS过渡能正常触发。

修改后的完整代码

import Section from '@/components/section'
import { Card, CardBody } from "@nextui-org/react";
import { useState } from 'react';

const Index = () => {
  const [expandedCard, setExpandedCard] = useState<number | null>(null);

  const handleCardClick = (index: number) => {
    setExpandedCard(index);
  };

  const cards = [
    { name: 'Tost', price: '140' },
    { name: 'Sendvic', price: '150' },
    { name: 'Sendvic', price: '150' },
    { name: 'Sendvic', price: '150' },
    { name: 'Sendvic', price: '150' },
    { name: 'Sendvic', price: '150' },
    { name: 'Sendvic', price: '150' },
    { name: 'Sendvic', price: '150' },
  ];

  return (
    <Page>
      <Section>
        {/* 外层容器,让展开卡片可以绝对定位覆盖网格 */}
        <div style={{ position: 'relative', width: '100%', minHeight: '30vh' }}>
          {/* 卡片网格区域 */}
          <div 
            style={{
              opacity: expandedCard !== null ? 0 : 1,
              transition: 'opacity 0.5s ease-in-out',
              pointerEvents: expandedCard !== null ? 'none' : 'auto', // 展开时禁用网格点击
            }}
          >
            <div className="grid grid-cols-2 gap-2 justify-center">
              {cards.map((card, index) => (
                <Card
                  key={index}
                  isPressable
                  onClick={() => handleCardClick(index)}
                >
                  <CardBody>
                    <img src="https://via.placeholder.com/200x150" alt="Placeholder Image" />
                    <div style={{
                      display: 'flex',
                      justifyContent: 'space-between',
                      alignItems: 'center',
                    }}>
                      <h5>{card.name}</h5>
                      <p>{card.price} RSD</p>
                    </div>
                  </CardBody>
                </Card>
              ))}
            </div>
          </div>

          {/* 展开卡片区域 */}
          {expandedCard !== null && (
            <div
              style={{
                position: 'absolute',
                top: 0,
                left: '50%',
                transform: expandedCard !== null ? 'translateX(-50%) scale(1)' : 'translateX(-50%) scale(0.9)',
                width: '90%',
                height: '30vh',
                backgroundColor: 'white',
                padding: '20px',
                borderRadius: '10px',
                boxShadow: '0px 0px 10px rgba(0, 0, 0, 0.2)',
                opacity: expandedCard !== null ? 1 : 0,
                transition: 'all 0.5s ease-in-out',
                zIndex: 10,
                display: 'flex',
                flexDirection: 'column',
                justifyContent: 'space-between'
              }}
            >
              <div>
                <h2>{cards[expandedCard].name}</h2>
                <p>{cards[expandedCard].price} RSD</p>
              </div>
              <button onClick={() => setExpandedCard(null)}>Close</button>
            </div>
          )}
        </div>
      </Section>
    </Page>
  );
};

export default Index

关键修改点

  1. 统一外层容器:用position: relative的容器包裹两个元素,让展开卡片可以绝对定位覆盖在网格上方。
  2. 保留DOM元素:不再用条件渲染切换组件,而是同时渲染网格和展开卡片(展开卡片用&&控制是否存在,但仅在第一次展开时挂载,之后只是样式变化)。
  3. 样式控制显隐:
    • 卡片网格:通过opacity控制透明度,展开时设为0,并添加pointerEvents: none防止误点击。
    • 展开卡片:初始opacity: 0+scale(0.9),展开时切换为opacity: 1+scale(1),配合transition: all 0.5s实现淡入+缩放的过渡效果。
  4. 修复原代码bug:原内部组件ExpandedCard无法直接调用setExpandedCard,改为直接在父组件渲染展开卡片,避免props传递问题。

进阶优化(可选)

  • 如果想让卡片网格的消失动画更自然,可以添加transform: translateY(20px)的过渡,让网格向下淡出。
  • 可以用NextUI的Modal组件替代自定义展开卡片,Modal自带过渡动画,更符合组件库的设计规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:58:12