2015-11-05 11 views
25

W Angular 1.x możemy użyć ngAnimate do wykrycia, kiedy wychodzimy lub wchodzimy na określoną trasę. Ponadto jesteśmy w stanie zastosować się do nich zachowań:Animacje przejścia strony z interfejsem Angular 2.0 i interfejsem komponentu obiecują

animateApp.animation('.myElement', function(){ 

    return { 

     enter : function(element, done) { 
      //Do something on enter 
     }, 

     leave : function(element, done) { 
      //Do something on leave 
     } 
    }; 

)}; 

wyniku których powstaje produkt tak: http://embed.plnkr.co/uW4v9T/preview

chciałbym zrobić coś podobnego z Kątowymi 2,0 i czuję, że jestem całkiem blisko .. .

Więc tu idzie, stworzyłem prosty router główny składnik aplikacji, który kontroluje nawigację pomiędzy domu i około komponentów.

import { bootstrap, bind, Component, provide, View } from 'angular2/angular2'; 
import {RouteConfig, RouteParams, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, APP_BASE_HREF, ROUTER_BINDINGS} from 'angular2/router' 




///////////////////////////////////////////////////////////////// 
// Home Component Start 
///////////////////////////////////////////////////////////////// 
@Component({ 
    selector: 'home-cmp' 
}) 

@View({ 
    template: ` 
    <h2 class="title">Home Page</h2> 
    ` 
}) 

class HomeCmp implements OnActivate, onDeactivate{ 

    onActivate(next: ComponentInstruction, prev: ComponentInstruction) { 
    console.log("Home Page - initialized"); 
    } 

    onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { 
    console.log("Home Page - destroyed"); 
    } 

} 
///////////////////////////////////////////////////////////////// 
// Home Component End 
///////////////////////////////////////////////////////////////// 




///////////////////////////////////////////////////////////////// 
// About Component Start 
///////////////////////////////////////////////////////////////// 
@Component({ 
    selector: 'about-cmp' 
}) 

@View({ 
    template: ` 
    <h2 class="title">About Page</h2> 
    ` 
}) 

class AboutCmp implements OnActivate, onDeactivate { 

    onActivate(next: ComponentInstruction, prev: ComponentInstruction) { 
    console.log("About Page - initialized"); 
    } 

    onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { 
    console.log("About Page - destroyed"); 
    } 

} 
///////////////////////////////////////////////////////////////// 
// About Component End 
///////////////////////////////////////////////////////////////// 




///////////////////////////////////////////////////////////////// 
// Main Application Componenent Start 
///////////////////////////////////////////////////////////////// 
@Component({ 
    selector: 'my-app' 
}) 

@View({ 
    template: ` 
    <div> 
     <h1>Hello {{message}}!</h1> 
     <a [router-link]="['./HomeCmp']">home</a> 
     <a [router-link]="['./AboutCmp']">about</a> 
     <hr> 
     <router-outlet></router-outlet> 
    </div> 
    `, 
    directives: [ROUTER_DIRECTIVES] 
}) 

@RouteConfig([ 
    {path: '/', component: HomeCmp, as: 'HomeCmp'}, 
    {path: '/about', component: AboutCmp, as: 'AboutCmp'} 
]) 

export class App { 
} 
///////////////////////////////////////////////////////////////// 
// Main Application Componenent End 
///////////////////////////////////////////////////////////////// 




bootstrap(App, [ 
    ROUTER_BINDINGS, 
    ROUTER_PROVIDERS, 
    ROUTER_DIRECTIVES, 
    provide(APP_BASE_HREF, {useValue: '/'}) 
]) 

W tej chwili jestem w stanie przechwycić, gdy router wyodrębnił lub zniszczył dany komponent, gdy przechodzi on z jednego do drugiego. To jest świetne, ale kiedy komponent poprzedni został zniszczony zniszczony, nie mogę zastosować animacji przejścia na urlopie, zanim zostanie zainicjowany następny komponent.

class HomeCmp implements OnActivate, onDeactivate{ 

    onActivate(next: ComponentInstruction, prev: ComponentInstruction) { 
     //This works 
     TweenMax.fromTo($(".title"), 1, {opacity: 0}, {opacity: 1}); 
    } 

    onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { 
     //This get ignored 
     TweenMax.fromTo($(".title"), 1, {opacity: 0}, {opacity: 1}); 
    } 

} 

Wygląda na to, że istnieje rozwiązanie tego problemu za pomocą obietnic. Podglądy API Angular.io zawierają:

Jeśli onDeactivate zwróci obietnicę, zmiana trasy będzie czekać, aż obietnica ustali się.

i

Jeśli onActivate zwraca obietnicę, zmiana trasy będzie czekać aż do wystąpienia obietnica osiada i aktywacji elementów podrzędnych.

https://angular.io/docs/ts/latest/api/

Jestem bardzo nowy do obietnic więc puree tym razem do mojego kodu, który rozwiązał problem mojego aktualnego składnika niszczona na inicjalizacji następnego, ale wtedy nigdy zostanie zniszczony , tworzy tylko nową jego instancję. Za każdym razem, gdy wrócę do niego, utworzy nową instancję, w wyniku której powstanie wiele kopii.

onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { 

    function ani(){ 
     TweenMax.fromTo($(".title"), 1, {opacity: 1}, {opacity: 0}); 
    } 

    var aniPromise = ani(); 

    aniPromise.then(function (ani) { 
     ani(); 
    }); 

} 

Przypomnę więc, router powinien być w stanie poczekać na zakończenie bieżącego składnika to firma przed niszcząc go i inicjuje kolejny składnik.

Mam nadzieję, że wszystko ma sens i naprawdę doceniam pomoc!

Odpowiedz

13

Jak zacytowałeś w dokumentach, jeśli któryś z tych haczyków zwróci Obietnicę, będzie czekał, aż zostanie ukończony, aby przejść do następnego, abyś mógł łatwo zwrócić Obietnicę, która zasadniczo nic nie robi i poczekać sekundę (lub wiele czasu, ile potrzebujesz).

onActivate(next: ComponentInstruction, prev: ComponentInstruction) { 
    TweenMax.fromTo($(".title"), 1, {opacity: 0}, {opacity: 1}); 
    return new Promise((res, rej) => setTimeout(() => res(1), 1000)); 
    } 

    onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { 
    TweenMax.fromTo($(".title"), 1, {opacity:1}, {opacity: 0}); 
    return new Promise((res, rej) => setTimeout(() => res(1), 1000)); 
    } 

Zauważ, że wracam obietnica, która biegnie do setTimeout.Czekamy sekundę, aby dać czas animacji na dokończenie.

Nie lubię używać setTimeouts, więc możemy również używać Observables, że osobiście najbardziej lubię.

return Rx.Observable.of(true).delay(1000).toPromise(); 

Tutaj jestem przekazując wartość losową (true w tym przypadku) i opóźnić jej drugi i wreszcie rzucić go do obietnicy. Tak, kończy się to byciem obietnicą, ale nie używam jej bezpośrednio.

Oto plnkr z przykładem pracy (oczekując tego, czego szukasz).

PS: Jeśli czasami skarży się na to, że nie może znaleźć ścieżki do Rx, po prostu odświeżaj, dopóki nie zadziała (dodałem Rx.js ręcznie i jest to trochę za ciężkie dla aplikanta plnkr).

+0

jesteś na miejscu dzięki za szybką i wyczerpującą odpowiedź! – SimonHawesome

+0

Cieszę się, że działało :) –

+0

Świetna odpowiedź! Zastanawiam się, czy istnieje sposób na "nakładanie się" animacji. Wydaje mi się, że to nie będzie takie proste, ponieważ pierwszy komponent powinien być ukryty (dezaktywowany), aby pokazać (aktywować) drugi. jakieś pomysły? –

9

kątowa 2 ostateczne rozwiązanie:

plunk

W skrócie, możemy użyć @routeAnimation wbudowany w dyrektywie, aby osiągnąć ten cel. Każdy z naszych elementów reprezentujących trasę dla dziecka zostanie ozdobiony w następujący sposób:

@Component({ 
    selector: 'app-pageone' 
    host: { '[@routeAnimation]': 'true' }, 
    styles: [':host { width: 300px; display: block; position: absolute; }'] 
    animations: [ 
    trigger('routeAnimation', [ 
     state('*', style({transform: 'translateX(0)', opacity: 1})), 
     transition('void => *', [ 
     style({transform: 'translateX(-100%)', opacity: 0}), 
     animate('0.5s cubic-bezier(0.215, 0.610, 0.355, 1.000)') 
     ]), 
     transition('* => void', 
     animate('0.5s cubic-bezier(0.215, 0.610, 0.355, 1.000)', style({ 
      transform: 'translateX(100%)', 
      opacity: 0 
     })) 
    ) 
    ]) 
    ] 
}) 
+0

'style: [': host {width: 300px; Blok wyświetlacza; pozycja: absolutna; } '] 'bit był bardzo potrzebny, miał trudności z uzyskaniem mojego, dopóki tego nie zobaczyłem, dzięki! – James

+2

Zamiast używać stylu na każdym komponencie, możesz również umieścić go w swoim css: 'router-outlet + * { position: absolute; szerokość: 100%; } ' – LVDM

+0

Czy można to zrobić bez' position: absolute; '? Ponieważ absolutna pozycja łamie moje oryginalne style. Dzięki! –