web-dev-qa-db-fra.com

Animation angulaire pour changeur de hauteur de façon dynamique

J'ai réussi à obtenir un panneau pour animer l'expansion et la fermeture lors de l'entrée et de la sortie du DOM. Le problème, c’est que j’ai maintenant un indicateur d’occupation dans le panneau avant d’afficher les détails. En outre, l’animation apparaît uniquement lorsqu’on ouvre l’indicateur d’occupation, et s’accroche lorsque le contenu détaillé est affiché.

Comment puis-je obtenir l'animation angulaire pour animer un changement de hauteur?

J'ai un exemple ici: https://plnkr.co/edit/Bs0rwp4ElidR75zN3ulR

trigger('expandCollapseDetails', [
    state('void', style({
        'height': '0px',
        overflow: 'hidden'
    })),
    //element being added into DOM.
    transition(':enter', [
        animate('500ms ease-in-out', style({
            'height': '*',
            overflow: 'hidden'
        }))
    ]),
    //element being removed from DOM.
    transition(':leave', [
        animate('500ms ease-in-out', style({
            'height': '0px',
            overflow: 'hidden'
        }))
    ])
])
6
Chris Moore

J'ai écrit un composant qui anime en douceur la hauteur du contenu projeté si ce contenu change… .. Il est utilisé comme ceci:

<smooth-height [trigger]="content">
  {{content}}
</smooth-height>

Voici un stackblitz: https://stackblitz.com/edit/angular4-kugxw7

C'est le composant:

import {ElementRef, HostBinding, Component, Input, OnChanges} from '@angular/core';
import {animate, style, transition, trigger} from "@angular/animations";

@Component({
  selector: 'smooth-height',
  template: `
    <ng-content></ng-content>
  `,
  styles: [`
    :Host {
      display: block;
      overflow: hidden;
    }
  `],
  animations: [
    trigger('grow', [
      transition('void <=> *', []),
      transition('* <=> *', [
        style({height: '{{startHeight}}px', opacity: 0}),
        animate('.5s ease'),
      ], {params: {startHeight: 0}})
    ])
  ]
})
export class SmoothHeightComponent implements OnChanges {
  @Input()
  trigger: string;

  startHeight: number;

  constructor(private element: ElementRef) {}  

  @HostBinding('@grow') get grow() {
    return {value: this.trigger, params: {startHeight: this.startHeight}};
  }

  setStartHeight(){
    this.startHeight = this.element.nativeElement.clientHeight;
  }

  ngOnChanges(){
    this.setStartHeight();
  }
}
9
Martin Cremer

J'ai fait une directive basée sur la réponse @MartinCremer. Je pense que l’utilisation d’une directive a plus de sens car en faisant cela, vous devriez aussi ajouter l’animation à votre composant parent (et c’est la méthode standard pour ajouter des animations).

Donc, dans mon fichier animations.ts. J'ai ajouté l'animation:

export const smoothHeight = trigger('grow', [
  transition('void <=> *', []),
  transition('* <=> *', [style({ height: '{{startHeight}}px', opacity: 0 }), animate('.5s ease')], {
    params: { startHeight: 0 }
  })
]);

alors vous devriez ajouter cette animation à votre composant parent (le composant avec lequel vous voulez utiliser l'animation):

import { smoothHeight } from '@app/animations';
@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss'],
  animations: [smoothHeight]
})

Et voici la directive qui est vraiment proche de la composante de @MartinCremer:

import { Directive, OnChanges, Input, HostBinding, ElementRef } from '@angular/core';

@Directive({
  selector: '[smoothHeight]',
  Host: { '[style.display]': '"block"', '[style.overflow]': '"hidden"' }
})
export class SmoothHeightAnimDirective implements OnChanges {
  @Input()
  smoothHeight;
  Pulse: boolean;
  startHeight: number;

  constructor(private element: ElementRef) {}

  @HostBinding('@grow')
  get grow() {
    return { value: this.Pulse, params: { startHeight: this.startHeight } };
  }

  setStartHeight() {
    this.startHeight = this.element.nativeElement.clientHeight;
  }

  ngOnChanges(changes) {
    this.setStartHeight();
    this.Pulse = !this.Pulse;
  }
}

Enfin, dans parent.component.html, utilisez la directive:

<div [smoothHeight]="yourAnimationIndicator">
  // any html content goes here
</div>

Il suffit de remplacer yourAnimationIndicator par la variable que l'animation doit déclencher lors du changement de sa valeur.

3
Vahid

Vous pouvez obtenir quelque chose de similaire avec un peu de css et de js:

Solution:

composant.ts

import { Component, OnChanges, ViewChild, Input } from '@angular/core';

@Component({
  selector: 'app-exandable',
  templateUrl: './exandable.component.html',
  styleUrls: ['./exandable.component.css']
})
export class ExandableComponent implements OnChanges {

  @Input()
  src;

  @ViewChild('expandable')
  expandable;

  ngOnChanges() {
    this.updateHeight();
  }

  updateHeight(delay = 0) {
    const el = this.expandable.nativeElement;

    setTimeout(() => {

      const prevHeight = el.style.height;
      el.style.height = 'auto';
      const newHeight = el.scrollHeight + 'px';
      el.style.height = prevHeight;

      setTimeout(() => {
        el.style.height = newHeight;
      }, 50);
    }, delay);
  }
}

css

.expandable {
  transition: height 0.2s ease-in-out;
  overflow: auto;
}

Code:

https://stackblitz.com/edit/angular-il71da

1
Kevin Upton