使用Angular 2.0路由器和组件接口承诺的页面转换动画

Sim*_*ome 25 promise typescript angular

在Angular 1.x中,我们可以使用ngAnimate来检测我们何时离开或进入特定路线.此外,我们可以对他们应用行为:

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

    return {

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

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

)};
Run Code Online (Sandbox Code Playgroud)

得到这样的产品:http://embed.plnkr.co/uW4v9T/preview

我想用Angular 2.0做类似的事情,我觉得我很接近......

所以这里去,我创建了一个用于控制与导航的主要应用组件一个简单的路由器家用有关部件.

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: '/'})
])
Run Code Online (Sandbox Code Playgroud)

目前,当路由器从一个组件移动到另一个组件时,我能够捕获特定组件的实例化或销毁.这很好,但是当前一个组件被销毁时,我无法在初始化下一个组件之前应用一个离开过渡动画.

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});
    }

}
Run Code Online (Sandbox Code Playgroud)

似乎使用承诺有一个解决方案.他们声明Angular.io的API预览:

如果onDeactivate返回一个promise,那么路由更改将等到promise结算.

如果onActivate返回一个promise,那么路由更改将一直等到promise实例化并激活子组件.

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

我是承诺的超级全新,所以我把它一起捣乱到我的代码中解决了我的当前组件在下一个的初始化时被破坏的问题,但是它永远不会被破坏,它只创建它的新实例.每次我导航回来,它都会创建一个新的实例,从而产生多个副本.

onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {

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

    var aniPromise = ani();

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

}
Run Code Online (Sandbox Code Playgroud)

所以回顾一下,路由器应该能够在销毁它并初始化下一个组件之前等待当前组件完成它的业务.

我希望一切都有道理,我真的很感激帮助!

Eri*_*nez 13

正如你从文档中引用的那样,如果这个钩子中的任何一个返回一个Promise,它将等到它完成后移动到下一个,所以你可以很容易地返回一个基本上什么都不做的Promise并等待一秒钟(或者等待你的时间)需要).

 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));
  }
Run Code Online (Sandbox Code Playgroud)

请注意,我正在返回一个运行setTimeout的Promise.我们等一下,给动画时间足够完成.

我真的不喜欢使用setTimeouts,所以我们也可以使用Observables,我个人最喜欢.

return Rx.Observable.of(true).delay(1000).toPromise();
Run Code Online (Sandbox Code Playgroud)

在这里,我传递一个随机值(在这种情况下为true)并将其延迟一秒,最后将其转换为Promise.是的,它最终是一个承诺,但我不直接使用它.

这是一个有一个例子工作的plnkr(期待你正在寻找的东西).

PS:如果有时它抱怨它无法找到Rx的路径,只需保持刷新直到它工作(我手动添加了Rx.js并且对于plnkr来说它有点重).


Ste*_*aul 9

Angular 2最终解决方案:

普拉克

简而言之,我们可以使用@routeAnimation内置指令来实现这一点.我们代表儿童路线的每个组件都将使用以下内容进行装饰:

@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
        }))
      )
    ])
  ]
})
Run Code Online (Sandbox Code Playgroud)

  • 你也可以把它放在你的css中:`router-outlet +*{position:absolute; 宽度:100%; }` (2认同)