Как я могу оживить * ngFor в Angular?

Мне нужно оживить список ngFor, поскольку он заполнен и показан. Каждый элемент должен иметь переход, скажем что-то вроде этого.

Как я могу это сделать?

Ответ 1

У него есть несколько проблем, потому что ngFor делает несколько избыточных ngFor добавления/удаления, которые приводят к анимации элементов, которые не должны:

import {Component} from 'angular2/core';
import { Component, Directive, OnDestroy, Input } from 'angular2/core';

@Component({
    selector: 'my-app',
    template: '<div (click)="$event.preventDefault()">
        <button type="button" (click)="pushItem()">Push</button>
        <button type="button" (click)="removeItemLast()">Remove Last</button><br/>
        <button type="button" (click)="unshiftItem()">Unshift</button>
        <button type="button" (click)="removeItemFirst()">Remove First</button><br/>
        <ul>
          <li class="my-animation" *ngFor="#item of items">
            {{item.title}}
          </li>
        </ul>
      </div>'
})
export class AppComponent {
  private count:number = 1;
  public items: Array<any>;
  constructor() { 
    console.clear(); 
    this.items = [];
    this.items.push(this.newItem());
    this.items.push(this.newItem());
    }
    pushItem() {
        this.items.push(this.newItem());
    },
    removeItemLast() {
      if(this.items.length > 0) this.items.splice(this.items.length - 1, 1);
    },
    unshiftItem() {
        this.items.unshift(this.newItem());
    },
    removeItemFirst() {
      if(this.items.length > 0) this.items.splice(0, 1);
    },
    newItem() {
      return {title: 'Item' + this.count++};
    }

}
@keyframes MyAnimation {
  0% {
    padding-left: 100px;
  }
  100% {
    padding-left: 0px;
  } 
}

.my-animation {
  animation: MyAnimation 1s;
}

Пример Plunker (RC.x) из https://github.com/angular/angular/issues/7239 демонстрирует проблему.

Обновить

Это было исправлено давно

рабочая демоверсия на stackblitz

Ответ 2

Теперь существует руководство к Angular анимационной системе. Это помогает, если мы хотим делать причудливые вещи, например, только анимацию для элементов, добавленных после инициализации компонента, а не те, которые уже присутствуют. Я изменил предыдущий ответ, чтобы сделать это Angular 2.

Plunker: http://plnkr.co/edit/NAs05FiAVTlUjDOZfEsF?p=preview

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

@Component({
    selector : 'my-app',
    animations: [
        trigger('growShrinkStaticStart', [
            state('in', style({ height: '*', 'padding-top': '*', 'padding-bottom': '*', 'margin-top': '*', 'margin-bottom': '*' })),
            transition('* => void', [
                style({ height: '*', 'padding-top': '*', 'padding-bottom': '*', 'margin-top': '*', 'margin-bottom': '*' }),
                animate("0.5s ease", style({ height: '0', 'padding-top': '0', 'padding-bottom': '0', 'margin-top': '0', 'margin-bottom': '0' }))
            ]),
            transition('void => false', [
                /*no transition on first load*/
            ]),
            transition('void => *', [
                style({ height: '0', 'padding-top': '0', 'padding-bottom': '0', 'margin-top': '0', 'margin-bottom': '0' }),
                animate("0.5s ease", style({ height: '*', 'padding-top': '*', 'padding-bottom': '*', 'margin-top': '*', 'margin-bottom': '*' }))
            ])
        ])
    ],
    template : `<div (click)="$event.preventDefault()">
        <button type="button" (click)="pushItem()">Push</button>
        <button type="button" (click)="removeItemLast()">Remove Last</button><br/>
        <button type="button" (click)="unshiftItem()">Unshift</button>
        <button type="button" (click)="removeItemFirst()">Remove First</button><br/>
        <ul style="background: light-blue">
          <li *ngFor="let item of items" 
          [@growShrinkStaticStart]="animationInitialized.toString()" 
          (@growShrinkStaticStart.done)="animationInitialized = true"
          style="background-color:pink; border:1px dashed gray; overflow:hidden">
            <h3>{{item.title}}</h3><p>{{item.description}}</p>
          </li>
        </ul>
        <div>Footer</div>
      </div>`
})
export class AppComponent
{
    private count: number = 1;
    public items: Array <{ title: string, description: string }> ;
    private animationInitialized: boolean = false;

    constructor() {
        this.items = [];
        this.items.push(this.newItem());
        this.items.push(this.newItem());
    }

    pushItem() {
        this.items.push(this.newItem());
    }

    removeItemLast() {
        if (this.items.length > 0)
            this.items.splice(this.items.length - 1, 1);
    }

    unshiftItem() {
        this.items.unshift(this.newItem());
    }

    removeItemFirst() {
        if (this.items.length > 0)
            this.items.splice(0, 1);
    }

    newItem() {
        let d: string = "";
        let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ    abcdefghijklmnopqrstuvwxyz0123456789 . ! ? ";

        for (let i = 0; i < Math.floor(Math.random() * 50000); i++)
            d += possible.charAt(Math.floor(Math.random() * possible.length));

        return { title : 'Item' + this.count++, description: d };
    }
}