【问题标题】:react-transition-group doesnt slideUp component React.jsreact-transition-group 不滑动组件 React.js
【发布时间】:2020-09-11 08:39:57
【问题描述】:

我有一个组件,当单击按钮时,具有更多信息的 div 将向上滑动和向下滑动。 下面是代码和css样式

import { CSSTransition } from "react-transition-group";
const Card = () => {
  const [showMoreInfo, setShowMoreInfo] = useState(false);

  return (
    <div className="Card">
      <ButtonShowMore isOpen={showMoreInfo} click={() => setShowMoreInfo(!showMoreInfo)} />
      <CSSTransition in={showMoreInfo} classNames="Card-Details" timeout={1000}>
        <div>
          {showMoreInfo && (
            <>
              <p>details</p>
              <p>details</p>
            </>
          )}
        </div>
      </CSSTransition>
    </div>
  );
};

.Card-Details-enter {
  height: 0px;
}

.Card-Details-enter-active {
  height: 100%;
  -webkit-transition: height 1s ease;
  -moz-transition: height 1s ease;
  -o-transition: height 1s ease;
  transition: height 1s ease;
}

.Card-Details-enter-done {
  height: 100%;
}

.Card-Details-exit {
  height: 100%;
}
.Card-Details-exit-active {
  height: 0px;
  -webkit-transition: height 1s ease;
  -moz-transition: height 1s ease;
  -o-transition: height 1s ease;
  transition: height 1s ease;
}
.Card-Details-exit-done {
  height: 0px;
}

但它不起作用,我不知道为什么。我想把过渡放到here这样的父元素 并像here 一样向 *-exit-done 类添加过渡,但没有任何帮助。

【问题讨论】:

    标签: css reactjs css-transitions


    【解决方案1】:

    它不起作用的原因是因为百分比高度的过渡并不是你所期望的。

    CSS 中的百分比高度和宽度指的是其父级的高度和宽度,而不是他们自己的高度。

    MDN Percentage

    CSS 数据类型表示百分比值。它是 通常用于定义相对于元素的父对象的大小。 许多属性都可以使用百分比,例如widthheightmarginpaddingfont-size

    使用百分比高度/宽度转换相同元素的示例。一个有一个高度/宽度为 50 像素的容器元素,另一个没有。

    div.container {
      width: 50px;
      height: 50px;
    }
    
    div.transition {
      width: 100%;
      height: 100%;
      background: red;
      transition: width 2s, height 4s;
    }
    
    div.transition:hover {
      width: 300%;
      height: 500%;
    }
    Transition div with a 50px container
    <div class="container">
      <div class="transition">
        <p>test</p>
      </div>
    </div>
    
    Transition div without a container:
    <div class="transition">
      <p>test</p>
    </div>

    我们真正想要的是从 0px 过渡到自动高度。不幸的是,浏览器不支持自动高度转换。

    Using CSS Transitions Auto Dimensions 中有一篇很好的文章,其中包括一些获得您想要的东西及其缺点的方法。

    为什么这个问题没有在浏览器级别解决?

    根据 Mozilla 开发者网络文档,自动值已 有意从 CSS 过渡规范中排除。看起来像 有几个人要求过,但仔细想想, 至少有点感觉它没有被包括在内。这 重新计算所有的大小和位置的浏览器进程 元素基于它们的内容以及它们与每个元素的交互方式 其他(称为“回流”)是昂贵的。如果你要转换一个 元素进入自动高度,浏览器必须执行 对该动画的每个阶段进行回流,以确定所有 其他元素应该移动。这不能被缓存或计算在 简单的方法,因为它不知道开始和/或结束值 直到过渡发生的那一刻。这将显着 使必须在幕后完成的数学复杂化,并且可能 以一种可能不明显的方式降低性能 开发者。

    How can I transition height: 0; to height: auto; using CSS? 也有一些很好的解决方法,尽管这确实没有灵丹妙药。

    这绝对是一个众所周知的问题,并且有一个 request 用于规范更改以允许自动转换,但我认为它还没有消失。


    至于对你在 React 过渡组中工作的过渡类型的支持:

    Slide Down AnimationTrying to fade out element then slide up 总体上都有相同的答案:指出React Bootstrap's Collapse component 是如何做到的。

    您需要依靠找到 dom 节点的实际高度并将其用作过渡的一部分:

      getDimension() {
        return typeof this.props.dimension === 'function'
          ? this.props.dimension()
          : this.props.dimension;
      }
    
      // for testing
      _getScrollDimensionValue(elem, dimension) {
        return `${elem[`scroll${capitalize(dimension)}`]}px`;
      }
    
      /* -- Expanding -- */
      handleEnter = (elem) => {
        elem.style[this.getDimension()] = '0';
      }
    
      handleEntering = (elem) => {
        const dimension = this.getDimension();
        elem.style[dimension] = this._getScrollDimensionValue(elem, dimension);
      }
    
      handleEntered = (elem) => {
        elem.style[this.getDimension()] = null;
      }
    
      /* -- Collapsing -- */
      handleExit = (elem) => {
        const dimension = this.getDimension();
        elem.style[dimension] = `${this.props.getDimensionValue(dimension, elem)}px`;
        triggerBrowserReflow(elem);
      }
    
      handleExiting = (elem) => {
        elem.style[this.getDimension()] = '0';
      }
    
    

    使用 Collapse 类中的功能的快速而肮脏的示例,用于使用功能较少的解决方案的代码工作示例(注意,主要基于上面链接的 Collapse.js 代码):

    const { Transition } = ReactTransitionGroup;
    const { EXITED, ENTERED, ENTERING, EXITING } = Transition;
    const { useState } = React;
    
    // Quick and dirty classNames functionality
    const classNames = (...names) => names.filter((name) => name).join(' ');
    
    const ButtonShowMore = ({ isOpen, click }) => {
      return <button onClick={click}>{isOpen ? 'Close' : 'Open'}</button>;
    };
    
    // Heavily based on https://github.com/react-bootstrap/react-bootstrap/blob/next/src/Collapse.js#L150
    // for the purpose of demonstration without just pulling in the module:
    
    function triggerBrowserReflow(node) {
      node.offsetHeight; // eslint-disable-line no-unused-expressions
    }
    
    const collapseStyles = {
      [EXITED]: 'collapse',
      [EXITING]: 'collapsing',
      [ENTERING]: 'collapsing',
      [ENTERED]: 'collapse in',
    };
    const Collapse = ({ children, ...props }) => {
      const handleEnter = (elem) => (elem.style.height = '0');
      const handleEntering = (elem) =>
        (elem.style.height = `${elem.scrollHeight}px`);
      const handleEntered = (elem) => (elem.style.height = null);
      const handleExit = (elem) => {
        elem.style.height = `${elem.scrollHeight}px`;
        triggerBrowserReflow(elem);
      };
      const handleExiting = (elem) => (elem.style.height = '0');
      return (
        <Transition
          {...props}
          onEnter={handleEnter}
          onEntering={handleEntering}
          onEntered={handleEntered}
          onExit={handleExit}
          onExiting={handleExiting}
        >
          {(state, innerProps) =>
            React.cloneElement(children, {
              ...innerProps,
              className: classNames(
                props.className,
                children.props.className,
                collapseStyles[state]
              ),
            })
          }
        </Transition>
      );
    };
    
    const Card = () => {
      const [showMoreInfo, setShowMoreInfo] = useState(false);
    
      return (
        <div className="Card">
          <ButtonShowMore
            isOpen={showMoreInfo}
            click={() => setShowMoreInfo(!showMoreInfo)}
          />
          <Collapse in={showMoreInfo} className="Card-Details" timeout={1000}>
            <div style={{ height: 0 }}>
              <p>details</p>
              <p>details</p>
            </div>
          </Collapse>
        </div>
      );
    };
    
    ReactDOM.render(<Card />, document.querySelector('#root'));
    .collapsing {
      -webkit-transition: height 1s ease;
      -moz-transition: height 1s ease;
      -o-transition: height 1s ease;
      transition: height 1s ease;
      overflow: hidden;
    }
    
    .collapse {
      overflow: hidden;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-transition-group/4.4.1/react-transition-group.min.js"></script>
    
    <div id="root" />

    【讨论】:

      猜你喜欢
      • 2018-05-27
      • 2017-12-31
      • 1970-01-01
      • 1970-01-01
      • 2019-10-11
      • 2020-07-04
      • 2018-02-06
      • 2018-02-09
      • 2020-09-09
      相关资源
      最近更新 更多