transition / animation angulaire 2 ngIf et CSS


121

Je veux qu'un div se glisse de la droite dans angular 2 en utilisant css.

  <div class="note" [ngClass]="{'transition':show}" *ngIf="show">
    <p> Notes</p>
  </div>
  <button class="btn btn-default" (click)="toggle(show)">Toggle</button>

Je fonctionne bien si je n'utilise que [ngClass] pour basculer entre la classe et utiliser l'opacité. Mais li ne veut pas que cet élément soit rendu depuis le début donc je le "cache" d'abord avec ngIf, mais la transition ne fonctionnera pas.

.transition{
  -webkit-transition: opacity 1000ms ease-in-out,margin-left 500ms ease-in-out;
  -moz-transition: opacity 1000ms ease-in-out,margin-left 500ms ease-in-out;
  -ms-transition: opacity 1000ms ease-in-out,margin-left 500ms ease-in-out ;
  -o-transition: opacity 1000ms ease-in-out,margin-left 500ms ease-in-out;
  transition: opacity 1000ms ease-in-out,margin-left 500ms ease-in-out;
  margin-left: 1500px;
  width: 200px;
  opacity: 0;
}

.transition{
  opacity: 100;
  margin-left: 0;
}

Réponses:


195

mise à jour 4.1.0

Plunker

Voir aussi https://github.com/angular/angular/blob/master/CHANGELOG.md#400-rc1-2017-02-24

mise à jour 2.1.0

Plunker

Pour plus de détails, voir Animations sur angular.io

import { trigger, style, animate, transition } from '@angular/animations';

@Component({
  selector: 'my-app',
  animations: [
    trigger(
      'enterAnimation', [
        transition(':enter', [
          style({transform: 'translateX(100%)', opacity: 0}),
          animate('500ms', style({transform: 'translateX(0)', opacity: 1}))
        ]),
        transition(':leave', [
          style({transform: 'translateX(0)', opacity: 1}),
          animate('500ms', style({transform: 'translateX(100%)', opacity: 0}))
        ])
      ]
    )
  ],
  template: `
    <button (click)="show = !show">toggle show ({{show}})</button>

    <div *ngIf="show" [@enterAnimation]>xxx</div>
  `
})
export class App {
  show:boolean = false;
}

original

*ngIfsupprime l'élément du DOM lorsque l'expression devient false. Vous ne pouvez pas avoir de transition sur un élément non existant.

Utilisez à la place hidden:

<div class="note" [ngClass]="{'transition':show}" [hidden]="!show">

2
Oui, caché ne fait que le rendre invisible mais l'élément existe toujours. *ngIfle supprime entièrement du DOM.
Günter Zöchbauer

1
C'est comme display:none. Il n'y a pas d' display:hiddenAFAIK.
Günter Zöchbauer

1
@ GünterZöchbauer oui, l'opacité est accélérée par le matériel donc elle conviendra mieux.
Ændri Domi

1
Ça ne fait rien. l'opacity ne supprimera pas l'élément et couvrira toujours les éléments en dessous, je suggère d'utiliser scale (0) qui affectera l'interface utilisateur comme display: none; mais avec une belle transition. Pour répondre à l'OP, il peut utiliser les animations angulaires angular.io/docs/ts/latest/guide/animations.html avec transform: scale (0) à l'état vide
Ændri Domi

1
Les éléments de déclenchement, de style, d'animation et de transition doivent maintenant être inclus à partir de @ angular / animations. Alors import{ trigger, style, animate, transition } from '@angular/animations';
Joel Hernandez

137

Selon la dernière documentation angular 2, vous pouvez animer des éléments "Entrée et sortie" (comme dans angular 1).

Exemple d'animation de fondu simple:

Dans @Component pertinent, ajoutez:

animations: [
  trigger('fadeInOut', [
    transition(':enter', [   // :enter is alias to 'void => *'
      style({opacity:0}),
      animate(500, style({opacity:1})) 
    ]),
    transition(':leave', [   // :leave is alias to '* => void'
      animate(500, style({opacity:0})) 
    ])
  ])
]

N'oubliez pas d'ajouter des importations

import {style, state, animate, transition, trigger} from '@angular/animations';

L'élément html du composant concerné doit ressembler à:

<div *ngIf="toggle" [@fadeInOut]>element</div>

J'ai construit un exemple d' animation de diapositives et de fondus ici .

Explication sur «void» et «*»:

  • voidest l'état lorsque ngIfest défini sur false (il s'applique lorsque l'élément n'est pas attaché à une vue).
  • *- Il peut y avoir de nombreux états d'animation (en savoir plus dans la documentation). L' *état est prioritaire sur tous en tant que "joker" (dans mon exemple, c'est l'état quand ngIfest défini sur true).

Remarque (tirée de la documentation angulaire):

Extra déclarer dans le module de l'application, import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

Les animations angulaires sont construites au-dessus de l'API Web Animations standard et s'exécutent en natif sur les navigateurs qui la prennent en charge. Pour les autres navigateurs, un polyfill est requis. Récupérez web-animations.min.js depuis GitHub et ajoutez-le à votre page.


2
Besoin d'importer le BrowserAnimationsModule pour utiliser des animations angulaires. Si je ne me trompe pas, le module d'animation a été trouvé dans le module de base d'angular 2 avant d'être déplacé vers son propre module, d'où la raison pour laquelle vous trouvez de nombreux exemples de plunker sans l'importation. Voici un plnkr mis à jour avec l'importation: Lien
snaplemouton

1
Lorsque vous utilisez une telle approche, l' leaveanimation n'a pas lieu, car le composant est supprimé du DOM *ngIfavant cela.
Slava Fomin II

4
Cela devrait être la réponse acceptée, cela donne en fait la solution à ceux qui veulent utiliser ngIf et non d'autres solutions de contournement.
Ovi Trif

17
    trigger('slideIn', [
      state('*', style({ 'overflow-y': 'hidden' })),
      state('void', style({ 'overflow-y': 'hidden' })),
      transition('* => void', [
        style({ height: '*' }),
        animate(250, style({ height: 0 }))
      ]),
      transition('void => *', [
        style({ height: '0' }),
        animate(250, style({ height: '*' }))
      ])
    ])

11

Solution CSS uniquement pour les navigateurs modernes

@keyframes slidein {
    0%   {margin-left:1500px;}
    100% {margin-left:0px;}
}
.note {
    animation-name: slidein;
    animation-duration: .9s;
    display: block;
}

Bonne alternative pour entrer la transition CSS uniquement. Utilisé ceci comme solution temporelle pour migrer à partir ng-enterde l'utilisation de classe.
edmundo096

4

Une façon consiste à utiliser un setter pour la propriété ngIf et à définir l'état dans le cadre de la mise à jour de la valeur.

Exemple de StackBlitz

fade.component.ts

 import {
    animate,
    AnimationEvent,
    state,
    style,
    transition,
    trigger
  } from '@angular/animations';
  import { ChangeDetectionStrategy, Component, Input } from '@angular/core';

  export type FadeState = 'visible' | 'hidden';

  @Component({
    selector: 'app-fade',
    templateUrl: './fade.component.html',
    styleUrls: ['./fade.component.scss'],
    animations: [
      trigger('state', [
        state(
          'visible',
          style({
            opacity: '1'
          })
        ),
        state(
          'hidden',
          style({
            opacity: '0'
          })
        ),
        transition('* => visible', [animate('500ms ease-out')]),
        transition('visible => hidden', [animate('500ms ease-out')])
      ])
    ],
    changeDetection: ChangeDetectionStrategy.OnPush
  })
  export class FadeComponent {
    state: FadeState;
    // tslint:disable-next-line: variable-name
    private _show: boolean;
    get show() {
      return this._show;
    }
    @Input()
    set show(value: boolean) {
      if (value) {
        this._show = value;
        this.state = 'visible';
      } else {
        this.state = 'hidden';
      }
    }

    animationDone(event: AnimationEvent) {
      if (event.fromState === 'visible' && event.toState === 'hidden') {
        this._show = false;
      }
    }
  }

fade.component.html

 <div
    *ngIf="show"
    class="fade"
    [@state]="state"
    (@state.done)="animationDone($event)"
  >
    <button mat-raised-button color="primary">test</button>
  </div>

example.component.css

:host {
  display: block;
}
.fade {
  opacity: 0;
}

3

J'utilise angular 5 et pour qu'un ngif fonctionne pour moi qui est dans un ngfor, j'ai dû utiliser animateChild et dans le composant user-detail, j'ai utilisé le * ngIf = "user.expanded" pour afficher hide user et cela a fonctionné pour entrer un départ

 <div *ngFor="let user of users" @flyInParent>
  <ly-user-detail [user]= "user" @flyIn></user-detail>
</div>

//the animation file


export const FLIP_TRANSITION = [ 
trigger('flyInParent', [
    transition(':enter, :leave', [
      query('@*', animateChild())
    ])
  ]),
  trigger('flyIn', [
    state('void', style({width: '100%', height: '100%'})),
    state('*', style({width: '100%', height: '100%'})),
    transition(':enter', [
      style({
        transform: 'translateY(100%)',
        position: 'fixed'
      }),
      animate('0.5s cubic-bezier(0.35, 0, 0.25, 1)', style({transform: 'translateY(0%)'}))
    ]),
    transition(':leave', [
      style({
        transform: 'translateY(0%)',
        position: 'fixed'
      }),
      animate('0.5s cubic-bezier(0.35, 0, 0.25, 1)', style({transform: 'translateY(100%)'}))
    ])
  ])
];

0

Dans mon cas, j'ai déclaré l'animation sur le mauvais composant par erreur.

app.component.html

  <app-order-details *ngIf="orderDetails" [@fadeInOut] [orderDetails]="orderDetails">
  </app-order-details>

L'animation doit être déclarée sur le composant où l'élément est utilisé dans ( appComponent.ts). Je déclarais OrderDetailsComponent.tsplutôt l'animation .

J'espère que cela aidera quelqu'un à faire la même erreur

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.