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

为React组件实现半秒展开过渡效果的技术咨询

实现半秒展开过渡的可行方案

你之前CSS过渡失败的核心原因是:当前代码在expanded状态切换时,是直接卸载/重新挂载组件(if (!expanded)直接返回按钮,否则返回展开内容),而CSS过渡需要元素始终存在于DOM中,通过样式变化触发动画。下面是两种可靠的实现方式:

方案一:纯CSS + React状态控制(无需额外库)

利用max-height、opacity结合CSS过渡,模拟高度变化的展开效果(适合内容高度不确定的场景):

步骤1:修改组件结构,保持展开内容始终在DOM中

const getFullMetricList = () =>
  Object.keys(comparisonChartsKeyMap)
    .map((category) => Object.values(comparisonChartsKeyMap[category]))
    .flat();

const MetricCatalog = ({ AddMetric, DeleteMetric, Metrics, width, height }) => {
  const [expanded, setExpanded] = useState(false);
  const [filteredMetricList, setFilteredMetricList] = useState(
    getFullMetricList()
  );

  const handleFuzzyFilterItems = (value) => {
    let newConf = matchSorter(getFullMetricList(), value);
    setFilteredMetricList(newConf);
  };

  const handleCloseCatalog = () => {
    setExpanded(false);
    setFilteredMetricList(getFullMetricList());
  };

  return (
    <div className="metric-catalog-wrapper">
      {/* 触发按钮 */}
      <div
        className='metric-catalog-btn-container'
        onClick={() => setExpanded(!expanded)}
      >
        Metric Catalog
      </div>
      {/* 展开内容容器,始终保留在DOM中 */}
      <div className={`metric-catalog-content ${expanded ? 'expanded' : ''}`}>
        {/* 这里放你的展开内容,比如过滤输入框、指标列表等 */}
        <input
          type="text"
          placeholder="搜索指标"
          onChange={(e) => handleFuzzyFilterItems(e.target.value)}
        />
        <ul>
          {filteredMetricList.map(metric => (
            <li key={metric}>{metric}</li>
          ))}
        </ul>
        <button onClick={handleCloseCatalog}>关闭</button>
      </div>
    </div>
  );
};

步骤2:添加CSS过渡样式

.metric-catalog-content {
  max-height: 0; /* 默认折叠状态,高度为0 */
  opacity: 0;
  overflow: hidden; /* 隐藏超出部分 */
  transition: max-height 0.5s ease, opacity 0.5s ease; /* 半秒过渡 */
  border: 1px solid #eee;
  padding: 0 16px;
}

.metric-catalog-content.expanded {
  max-height: 500px; /* 设置足够大的值覆盖内容最大高度 */
  opacity: 1;
  padding: 16px; /* 展开时恢复内边距 */
}

说明:通过max-height的变化模拟高度展开动画,设置足够大的目标值确保能容纳所有内容,过渡时长设为0.5秒符合需求。

方案二:使用React Transition Group(适合复杂动画场景)

如果需要更精细的入场/离场动画控制,可以用React官方推荐的react-transition-group库:

步骤1:安装依赖

npm install react-transition-group

步骤2:修改组件代码

import { CSSTransition } from 'react-transition-group';

const getFullMetricList = () =>
  Object.keys(comparisonChartsKeyMap)
    .map((category) => Object.values(comparisonChartsKeyMap[category]))
    .flat();

const MetricCatalog = ({ AddMetric, DeleteMetric, Metrics, width, height }) => {
  const [expanded, setExpanded] = useState(false);
  const [filteredMetricList, setFilteredMetricList] = useState(
    getFullMetricList()
  );

  const handleFuzzyFilterItems = (value) => {
    let newConf = matchSorter(getFullMetricList(), value);
    setFilteredMetricList(newConf);
  };

  const handleCloseCatalog = () => {
    setExpanded(false);
    setFilteredMetricList(getFullMetricList());
  };

  return (
    <div className="metric-catalog-wrapper">
      <div
        className='metric-catalog-btn-container'
        onClick={() => setExpanded(!expanded)}
      >
        Metric Catalog
      </div>
      {/* 使用CSSTransition包裹展开内容 */}
      <CSSTransition
        in={expanded}
        timeout={500}
        classNames="catalog-transition"
        unmountOnExit
      >
        <div className="metric-catalog-content">
          <input
            type="text"
            placeholder="搜索指标"
            onChange={(e) => handleFuzzyFilterItems(e.target.value)}
          />
          <ul>
            {filteredMetricList.map(metric => (
              <li key={metric}>{metric}</li>
            ))}
          </ul>
          <button onClick={handleCloseCatalog}>关闭</button>
        </div>
      </CSSTransition>
    </div>
  );
};

步骤3:添加过渡样式

/* 入场初始状态 */
.catalog-transition-enter {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  padding: 0 16px;
}

/* 入场动画执行中 */
.catalog-transition-enter-active {
  max-height: 500px;
  opacity: 1;
  padding: 16px;
  transition: max-height 0.5s ease, opacity 0.5s ease;
}

/* 离场初始状态 */
.catalog-transition-exit {
  max-height: 500px;
  opacity: 1;
  overflow: hidden;
  padding: 16px;
}

/* 离场动画执行中 */
.catalog-transition-exit-active {
  max-height: 0;
  opacity: 0;
  padding: 0 16px;
  transition: max-height 0.5s ease, opacity 0.5s ease;
}

.metric-catalog-content {
  border: 1px solid #eee;
}

说明:unmountOnExit会在离场动画结束后自动卸载内容组件,避免DOM冗余;库会自动根据状态切换添加对应的样式类,实现流畅的过渡效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:45:35