Dans Angular 1.x, nous pouvons utiliser ngAnimate pour détecter quand nous quittons ou entrons dans une route particulière. De plus, nous pouvons leur appliquer des comportements:
animateApp.animation('.myElement', function(){
return {
enter : function(element, done) {
//Do something on enter
},
leave : function(element, done) {
//Do something on leave
}
};
)};
Il en résulte un produit comme celui-ci: http://embed.plnkr.co/uW4v9T/preview
Je voudrais faire quelque chose de similaire avec Angular 2.0 et j'ai l'impression d'être assez proche ...
Alors voilà, j'ai créé un simple routeur dans le composant principal de l'application qui contrôle la navigation entre les composants home et about.
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: '/'})
])
Pour le moment, je peux capturer lorsque le routeur a instancié ou détruit un composant particulier lorsqu'il passe de l'un à l'autre. C'est très bien, mais lorsque le composant précédent est détruit Je ne suis pas en mesure d'appliquer une animation de transition en congé avant l'initialisation du composant suivant.
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});
}
}
Il semble qu'il y ait une solution à cela en utilisant des promesses. Aperçu de l'API d'Angular.io, ils déclarent:
Si onDeactivate renvoie une promesse, le changement de route attendra que la promesse soit réglée.
et
Si onActivate renvoie une promesse, le changement de route attendra que la promesse s'installe pour instancier et activer les composants enfants.
https://angular.io/docs/ts/latest/api/
Je suis super flambant neuf aux promesses, j'ai donc écrasé cela ensemble dans mon code, ce qui a résolu le problème de la destruction de mon composant actuel lors de l'initialisation du suivant, mais il jamais est détruit, seulement en crée une nouvelle instance. Chaque fois que j'y reviens, cela crée une nouvelle instance entraînant plusieurs copies.
onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
function ani(){
TweenMax.fromTo($(".title"), 1, {opacity: 1}, {opacity: 0});
}
var aniPromise = ani();
aniPromise.then(function (ani) {
ani();
});
}
Donc, pour récapituler, le routeur devrait être en mesure d'attendre que le composant actuel ait terminé c'est business avant de le détruire et d'initialiser le composant suivant.
J'espère que tout a du sens et j'apprécie vraiment l'aide!
Comme vous l'avez cité dans la documentation, si l'un de ces crochets renvoie une promesse, il attendra jusqu'à ce qu'elle soit terminée pour passer à la suivante, vous pouvez donc facilement retourner une promesse qui ne fait rien et attendre une seconde (ou autant de fois que vous avoir besoin).
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));
}
Notez que je retourne une promesse qui exécute un setTimeout. Nous attendons une seconde pour donner suffisamment de temps à l'animation pour être terminée.
Je n'aime pas vraiment utiliser setTimeouts, donc nous pouvons aussi utiliser Observables, que personnellement j'aime le mieux.
return Rx.Observable.of(true).delay(1000).toPromise();
Ici, je passe une valeur aléatoire (vrai dans ce cas) et la retarde une seconde et finalement la jette sur Promise. Oui, cela finit par être une promesse mais je ne l'utilise pas directement.
Voici un plnkr avec un exemple de travail (en espérant être ce que vous recherchez).
PS: Si parfois il se plaint de ne pas trouver de chemin vers Rx, continuez à rafraîchir jusqu'à ce qu'il fonctionne (j'ai ajouté Rx.js manuellement et c'est un peu lourd pour plnkr).
Solution finale angulaire 2:
En un mot, nous pouvons utiliser le @routeAnimation
directive intégrée pour y parvenir. Chacun de nos composants représentant un parcours enfant sera décoré de quelque chose comme:
@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
}))
)
])
]
})