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



我正在尝试用CCD_ 1制作元素高度的动画,所以这就是我想要的动画外观:

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

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

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

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

应该是因为询问node.scrollHeight导致渲染立即发生,所以在动画开始之前是否有获得相同信息并注入css规则的方法?或者我应该反过来想?

我对max-height的解决方案不太满意,因为当max-height不接近或小于height时,生成的动画速度会非常奇怪,而且我的组件的高度确实变化很大。

我可以想象最终的解决方案可能有点混乱,但我认为将其制作成Mixin将足够好,可以在任何地方重复使用

我也遇到了同样的问题,最终编写了一个用于设置高度动画的独立组件。

您可以在此处看到演示: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>

很抱歉这种无耻的自我推销,但我认为如果你有多个组件要制作动画,可以节省你很多时间。

干杯!

经过更多的实验,我提出了一个解决方案,使用低级别的API ReactCSSTransitionGroup0而不是高级别的ReactCSSTransitionGroup

以下是具有工作解决方案的JSFiddle:http://jsfiddle.net/cherrry/0wgp34cr/

在动画之前,它做了3件事:

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

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

  1. 取消隐藏元素
  2. 添加.anim-enter-active以启动动画

JSFiddle中的一些数字和类名是硬编码的,但将"mixin"转换为React类作为ReactCSSTransitionGroup的替代应该足够容易

一个非常简单而好的方法是处理scaleY而不是高度。悬停应设置属性transform:scaleY(1)(最初为=>transform:scaleY(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()}>
                    {title}
                </h2>
                <div
                    ref={this.setInnerRef}
                    onTransitionEnd={() => this.updateAfterTransition()}
                    style={{
                        height: this.state.height,
                        overflow: "hidden",
                        transition: "height 250ms linear 0s",
                    }}
                >
                    {children}
                </div>
            </div>
        );
    }
}

最新更新