使用 Angular 2.0 路由器和组件接口承诺的页面转换动画 [英] Page transition animations with Angular 2.0 router and component interface promises

查看:15
本文介绍了使用 Angular 2.0 路由器和组件接口承诺的页面转换动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

animateApp.animation('.myElement', function(){返回 {输入:函数(元素,完成){//在输入时做一些事情},离开:功能(元素,完成){//请假做点什么}};)};

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

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

因此,我在主应用程序组件中创建了一个简单的路由器,用于控制 homeabout 组件之间的导航.

import { bootstrap, bind, Component, provide, View } from 'angular2/angular2';从angular2/router"导入 {RouteConfig, RouteParams, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, APP_BASE_HREF, ROUTER_BINDINGS}///////////////////////////////////////////////////////////////////主页组件启动/////////////////////////////////////////////////////////////////@零件({选择器:'home-cmp'})@看法({模板:`<h2 class="title">主页</h2>`})类 HomeCmp 实现 OnActivate、onDeactivate{onActivate(next: ComponentInstruction, prev: ComponentInstruction) {console.log("主页 - 已初始化");}onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {console.log("主页 - 已销毁");}}///////////////////////////////////////////////////////////////////主组件结束////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////关于组件启动/////////////////////////////////////////////////////////////////@零件({选择器:'关于-cmp'})@看法({模板:`<h2 class="title">关于页面</h2>`})类 AboutCmp 实现 OnActivate、onDeactivate {onActivate(next: ComponentInstruction, prev: ComponentInstruction) {console.log("关于页面 - 已初始化");}onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {console.log("关于页面 - 已销毁");}}///////////////////////////////////////////////////////////////////关于组件端////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////主应用组件启动/////////////////////////////////////////////////////////////////@零件({选择器:'我的应用'})@看法({模板:`<div><h1>你好{{message}}!</h1><a [router-link]="['./HomeCmp']">home</a><a [router-link]="['./AboutCmp']">关于</a><小时><路由器插座></路由器插座>

`,指令:[ROUTER_DIRECIVES]})@RouteConfig([{path: '/', 组件: HomeCmp, as: 'HomeCmp'},{path: '/about', 组件: AboutCmp, as: 'AboutCmp'}])出口类应用{}///////////////////////////////////////////////////////////////////主应用组件端/////////////////////////////////////////////////////////////////引导程序(应用程序,[ROUTER_BINDINGS,ROUTER_PROVIDERS,路由器_指令,提供(APP_BASE_HREF,{useValue:'/'})])

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

class HomeCmp 实现 OnActivate、onDeactivate{onActivate(next: ComponentInstruction, prev: ComponentInstruction) {//这有效TweenMax.fromTo($(".title"), 1, {opacity: 0}, {opacity: 1});}onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {//这个被忽略TweenMax.fromTo($(".title"), 1, {opacity: 0}, {opacity: 1});}}

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

如果onDeactivate返回一个promise,路由改变将等到promise解决.

如果onActivate返回一个promise,路由改变将等到promise解决后实例化并激活子组件.

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

我对 Promise 非常陌生,所以我将它混合到我的代码中,这解决了我当前组件在下一个初始化时被销毁的问题,但是它永远不会被销毁,它只创建它的一个新实例.每次我导航回它时,它都会创建一个新实例,从而产生多个副本.

onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {函数 ani(){TweenMax.fromTo($(".title"), 1, {opacity: 1}, {opacity: 0});}var aniPromise = ani();aniPromise.then(function (ani) {阿尼();});}

总结一下,路由器应该能够等待当前组件完成它的业务,然后再销毁它并初始化下一个组件.

我希望一切都有意义,我非常感谢您的帮助!

解决方案

正如你从文档中引用的那样,如果这个钩子中的任何一个返回一个 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));}

请注意,我正在返回一个运行 setTimeout 的 Promise.我们稍等片刻,让动画有足够的时间完成.

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

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

这里我传递了一个随机值(在本例中为 true)并延迟一秒钟,最后将其转换为 Promise.是的,它最终是一个 Promise,但我不直接使用它.

这是一个 plnkr 和一个工作示例(预计是您正在寻找的).

PS:如果有时它抱怨找不到 Rx 的路径,请保持刷新,直到它起作用为止(我手动添加了 Rx.js,这对于 plnkr 来说似乎有点沉重).

In Angular 1.x we can use ngAnimate to detect when we are leaving or entering a particular route. Furthermore we are able to apply behaviors to them:

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

    return {

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

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

)};

Resulting in a product like this: http://embed.plnkr.co/uW4v9T/preview

I would like to do something similar with Angular 2.0 and I feel like I'm pretty close...

So here goes, I've created a simple router in the main application component that controls the navigation between the home and about components.

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: '/'})
])

At the moment I am able to capture when the router has instantiated or destroyed a particular component when it moves from one to the next. This is great, but when the the previous component is destroyed I am not able to apply an on leave transition animation before the next component is initialized.

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

}

It seems like there is a solution to this using promises. Angular.io's API preview they state:

If onDeactivate returns a promise, the route change will wait until the promise settles.

and

If onActivate returns a promise, the route change will wait until the promise settles to instantiate and activate child components.

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

I am super brand new to promises so I mashed this together into my code which solved the problem of my current component being destroyed on initialization of the next one, but then it never gets destroyed, it only creates a new instance of it. Every time I navigate back to it, it will create a new instance resulting in multiple copies.

onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {

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

    var aniPromise = ani();

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

}

So to recap, the router should be able to wait for the current component to finish it's business before destroying it and initializing the next component.

I hope that all makes sense and I really appreciate the help!

解决方案

As you quoted from the docs, if any of this hooks returns a Promise it will wait until its completed to move to the next one, so you can easily return a Promise that basically does nothing and wait a second (or as many time as you need).

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

Note that I'm returning a Promise which runs a setTimeout. We wait a second to give the animation time enough to be completed.

I don't really like using setTimeouts, so we can use Observables as well, that personally I like the best.

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

Here I'm passing a random value (true in this case) and delay it a second and finally cast it to Promise. Yes, it ends up being a Promise but I don't use it directly.

Here's a plnkr with an example working (expecting to be what you are looking for).

PS: If sometimes it complains about that it can't find a path to Rx, just keep refreshing until it works (I added Rx.js manually and it's a little heavy for plnkr apprently).

这篇关于使用 Angular 2.0 路由器和组件接口承诺的页面转换动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆