如何使用ReactCSSTransitionGroup在React中为元素高度设置动画?

时间:2015-03-30 01:23:31

标签: reactjs actualheight reactcsstransitiongroup

我正在尝试使用ReactCSSTransitionGroup设置元素高度的动画, 所以这就是我想要的动画:

http://jsfiddle.net/cherrry/hgk4Lme9/

问题是我并不总是知道元素高度, 所以我试图在scrollHeight期间破解clientHeightcomponentDidMount或类似内容,并尝试设置node.style.height或向样式表添加规则

http://jsfiddle.net/cherrry/dz8uod7u/

让动画看起来不错,但是当元素进入时,它会闪一点,缩放动画看起来很奇怪

应该是因为要求node.scrollHeight导致渲染立即发生,所以无论如何都要获得相同的信息并在动画开始之前注入css规则?或者我应该考虑其他方式?

我对max-height解决方案不是很满意,因为当max-height不接近或小于height时,结果动画速度会非常奇怪,而且我的组件'身高差异很大。

我可以想象最终的解决方案可能有点凌乱, 但是我觉得把它变成一个Mixin就足够了,可以在任何地方重复使用

3 个答案:

答案 0 :(得分:17)

经过一些实验后,我使用低级API ReactTransitionGroup代替高级ReactCSSTransitionGroup

来提出解决方案

这里是JSFiddle的工作解决方案:http://jsfiddle.net/cherrry/0wgp34cr/

在动画制作之前,它做了三件事:

  1. 获得计算的高度,填充和边距
  2. 使用display: none隐藏元素并添加.anim-enter以将高度设置为0
  3. .anim-enter-active
  4. 创建css规则

    要开始动画,它会做两件事:

    1. 取消隐藏元素
    2. 添加.anim-enter-active以启动动画
    3. JSFiddle中的一些数字和类名是硬编码的,但它应该很容易改变" mixin"在React类中替换ReactCSSTransitionGroup

答案 1 :(得分:12)

我遇到了同样的问题,最后为动画高度编写了一个独立的组件。

您可以在此处查看演示: https://stanko.github.io/react-animate-height/

它更容易使用,整个库非常小(约200行)

<AnimateHeight
  duration={ 500 }
  height={ 'auto' }
>
  <h1>Your content goes here</h1>
  <p>Put as many React or HTML components here.</p>
</AnimateHeight>

对于无耻的自我推销感到抱歉,但如果您有多个组件可以动画,我认为它可以为您节省大量时间。

干杯!

答案 2 :(得分:0)

如果您不想导入模块或使用qjuery,这是使用React ref(https://reactjs.org/docs/refs-and-the-dom.html)的模板

基本上,您会得到将要达到的高度,增长到该高度,然后切换回自动。在返回的途中,将其切换为高度,然后返回至0。

class CollapsibleSectionBlock extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        showContent: false,
        height: "0px",
        myRef: null,
    };
}

componentDidUpdate = (prevProps, prevState) => {
    if (prevState.height === "auto" && this.state.height !== "auto") {
        setTimeout(() => this.setState({ height: "0px" }), 1);
    }
}

setInnerRef = (ref) => this.setState({ myRef: ref });

toggleOpenClose = () => this.setState({
    showContent: !this.state.showContent,
    height: this.state.myRef.scrollHeight,
});

updateAfterTransition = () => {
    if (this.state.showContent) {
        this.setState({ height: "auto" });
    }
};

render() {
    const { title, children } = this.props;
    return (
        <div>
            <h2 onClick={() => this.toggleOpenClose()}>
                Example
            </h2>
            <div
                ref={this.setInnerRef}
                onTransitionEnd={() => this.updateAfterTransition()}
                style={{
                    height: this.state.height,
                    overflow: "hidden",
                    transition: "height 250ms linear 0s",
                }}
            >
                {children}
            </div>
        </div>
    );
}

}