web-dev-qa-db-fra.com

Comment animer la hauteur d'un élément dans React avec ReactCSSTransitionGroup?

J'essaie d'animer la hauteur des éléments avec ReactCSSTransitionGroup, voici donc à quoi je voudrais que l'animation ressemble:

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

Le problème est que je ne connais pas toujours la hauteur de l'élément, j'ai donc essayé de pirater les scrollHeight, clientHeight ou quelque chose de similaire pendant componentDidMount et d'essayer de définir node.style.height ou ajouter des règles à la feuille de style

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

Quitter l'animation semble bon, mais lorsque l'élément entre, il clignote un peu et l'animation de mise à l'échelle semble étrange

Cela devrait être dû à la demande de node.scrollHeight a provoqué le rendu immédiatement, est-il donc possible d'obtenir les mêmes informations et d'injecter des règles CSS avant le démarrage de l'animation? Ou devrais-je penser autrement?

Je ne suis pas très satisfait du max-height solution, car la vitesse d'animation résultante sera très étrange lorsque max-height n'est pas proche ou inférieur à height, et la hauteur de mes composants varie beaucoup.

Je pourrais imaginer que la solution finale pourrait être un peu compliquée, mais je pense qu'en faire un Mixin sera assez agréable pour la réutiliser n'importe où

20
Cherry Ng

J'ai eu le même problème et j'ai fini par écrire un composant autonome pour animer la hauteur.

Vous pouvez voir la démo ici: https://stanko.github.io/react-animate-height/

Il est beaucoup plus facile à utiliser et la bibliothèque entière est vraiment petite (~ 200 lignes)

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

Désolé pour l'auto-promotion éhontée, mais je pense que cela peut vous faire gagner beaucoup de temps si vous avez plus d'un composant à animer.

À votre santé!

15
Stanko

Après un peu plus d'expérience, j'ai trouvé une solution en utilisant l'API de bas niveau ReactTransitionGroup au lieu de haut niveau ReactCSSTransitionGroup

Voici le JSFiddle avec une solution de travail: http://jsfiddle.net/cherrry/0wgp34cr/

Avant l'animation, il fait 3 choses:

  1. obtenir la hauteur, les rembourrages et les marges calculés
  2. masquer l'élément avec display: none et ajouter .anim-enter pour régler la hauteur sur 0
  3. créer une règle css pour .anim-enter-active

Pour démarrer l'animation, cela fait 2 choses:

  1. afficher l'élément
  2. ajouter .anim-enter-active pour démarrer l'animation

Certains numéros et noms de classe dans JSFiddle étaient codés en dur, mais il devrait être assez facile de transformer le "mixin" en une classe React en remplacement de ReactCSSTransitionGroup

17
Cherry Ng

Si vous ne voulez pas importer un module ou utiliser qjuery, voici un modèle utilisant React ref ( https://reactjs.org/docs/refs-and-the-dom .html )

Fondamentalement, vous obtenez la hauteur qu'elle sera, atteignez cette hauteur, revenez à auto. Sur le chemin du retour, passez à la hauteur, puis revenez à 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