web-dev-qa-db-ja.com

React ReactCSSTransitionGroupで要素の高さをアニメーション化する方法は?

要素の高さをReactCSSTransitionGroupでアニメーション化しようとしているので、アニメーションは次のようにします。

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

問題は、要素の高さが常にわからないことです。そのため、scrollHeightの間にclientHeightcomponentDidMountなどをハックして、node.style.heightまたはスタイルシートにルールを追加

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

アニメーションを残すと見栄えがよくなりますが、要素が入ると少し点滅し、スケーリングアニメーションが奇妙に見えます

これは、node.scrollHeightに要求されたためにレンダリングがすぐに発生するためです。アニメーションを開始する前に、同じ情報を取得してCSSルールを挿入する方法はありますか?または私は逆に考える必要がありますか?

max-heightheightに近いか、それよりも小さく、コンポーネントの高さがそうでない場合、結果のアニメーション速度が非常に奇妙になるため、max-heightソリューションにはあまり満足していません。大きく異なります。

最終的なソリューションが少し面倒になる可能性があると想像できましたが、それをMixinにすることは、どこにでも再利用できるほど十分だと思います

20
Cherry Ng

同じ問題があり、高さをアニメーション化するためのスタンドアロンコンポーネントを作成することになりました。

ここでデモを見ることができます: 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>

恥知らずな自己宣伝は申し訳ありませんが、アニメーション化するコンポーネントが複数ある場合は、時間を大幅に節約できると思います。

乾杯!

15
Stanko

もう少し実験した後、高レベルのReactTransitionGroupではなく低レベルのAPI ReactCSSTransitionGroupを使用して解決策を考え出しました

これが動作するソリューションを備えたJSFiddleです: http://jsfiddle.net/cherrry/0wgp34cr/

アニメーションの前に、3つのことを行っています。

  1. 計算された高さ、パディング、マージンを取得する
  2. display: noneで要素を非表示にし、.anim-enterを追加して高さを0に設定します
  3. .anim-enter-activeのCSSルールを作成

アニメーションを開始するには、次の2つのことを行います。

  1. 要素を再表示する
  2. .anim-enter-activeを追加してアニメーションを開始します

JSFiddleの一部の数値とクラス名はハードコーディングされていましたが、「mixin」をReactCSSTransitionGroupの代わりにReactクラスに変換するのは簡単です。

17
Cherry Ng

モジュールをインポートしたくない場合や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>
    );
}

}

1
blindguy