Reactjs 如何在React with ReactCSTransanitionGroup中设置元素高度的动画?

Reactjs 如何在React with ReactCSTransanitionGroup中设置元素高度的动画?,reactjs,actualheight,reactcsstransitiongroup,Reactjs,Actualheight,Reactcsstransitiongroup,我正在尝试使用reactcstransitiongroup设置元素高度的动画, 这就是我想要动画的样子: 问题是我并不总是知道元素的高度, 因此,我尝试在组件安装期间破解滚动高度,clientHeight或类似的东西,并尝试设置节点.style.height或向样式表添加规则 离开动画看起来不错,但是当元素进入时,它会闪烁一点,缩放动画看起来很奇怪 这应该是因为询问节点。scrollHeight导致渲染立即发生,所以在动画开始之前,是否仍然可以获得相同的信息并注入css规则?或者我应该换个角

我正在尝试使用
reactcstransitiongroup
设置元素高度的动画, 这就是我想要动画的样子:

问题是我并不总是知道元素的高度, 因此,我尝试在
组件安装期间破解
滚动高度
clientHeight
或类似的东西,并尝试设置
节点.style.height
或向样式表添加规则

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

这应该是因为询问
节点。scrollHeight
导致渲染立即发生,所以在动画开始之前,是否仍然可以获得相同的信息并注入css规则?或者我应该换个角度思考

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

我可以想象最终的解决方案会有点混乱,
但是我认为把它变成一个Mixin就足够好了,可以在任何地方重用它

经过更多的实验,我想出了一个解决方案,使用低级API
ReactTransitionGroup
而不是高级
ReactCSTranslationGroup

下面是JSFIDLE,它提供了一个有效的解决方案:

在制作动画之前,它要做3件事:

  • 获取计算的高度、填充和边距
  • 使用
    display:none
    隐藏元素并添加
    。anim enter
    将高度设置为0
  • 创建css规则。动画输入active
  • 要开始动画,它需要做两件事:

  • 取消隐藏元素
  • 添加
    .anim输入active
    以启动动画

  • JSFIDLE中的一些数字和类名是硬编码的,但是将“mixin”转换为React类来代替React CSTransanizingGroup应该很容易,因为我遇到了同样的问题,最后编写了一个独立的组件来设置高度动画

    您可以在此处看到演示:

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

    
    你的内容放在这里
    在此处放置尽可能多的React或HTML组件

    很抱歉进行无耻的自我宣传,但我认为如果你有多个组件需要制作动画,那么它可以为你节省很多时间


    干杯

    如果您不想导入模块或使用qjuery,这里有一个使用React ref()的模板

    基本上你得到了它的高度,增长到那个高度,切换回自动。在返回的过程中,切换到当前高度,然后返回到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>
        );
    }
    
    类可折叠分段块扩展React.Component{
    建造师(道具){
    超级(道具);
    此.state={
    showContent:false,
    高度:“0px”,
    myRef:null,
    };
    }
    componentDidUpdate=(prevProps,prevState)=>{
    如果(prevState.height==“自动”&&this.state.height!==“自动”){
    setTimeout(()=>this.setState({height:“0px”}),1);
    }
    }
    setInnerRef=(ref)=>this.setState({myRef:ref});
    toggleOpenClose=()=>this.setState({
    showContent:!this.state.showContent,
    高度:this.state.myRef.scrollHeight,
    });
    updateAfterTransition=()=>{
    if(this.state.showContent){
    this.setState({height:“auto”});
    }
    };
    render(){
    const{title,children}=this.props;
    返回(
    this.toggleOpenClose()}>
    例子
    this.updateAfterTransition()}
    风格={{
    高度:this.state.height,
    溢出:“隐藏”,
    过渡:“高度250ms线性0s”,
    }}
    >
    {儿童}
    );
    }
    

    }

    嗯,这并不是你解释过的无耻的自我推销。好的。但是回答老问题时要小心。谢谢,我不知道这是个老问题,我的错!我喜欢react动画高度,但如何在宽度上获得相同的效果。这在使用react样式编程时不起作用,即
    {This.state.show?:null}
    当然不起作用。使用此选项:
    animatehight负责可访问性并隐藏内容。
    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>
        );
    }