如何在导航到下一个路线之前等待动画结束?

时间:2018-04-18 18:32:50

标签: angular

我尝试了this解决方案,但似乎对我不起作用。

我所做的是(或多或少)将this example中的代码实现到我的客户端。但是,我来自另一条路线。我想从/login导航到/home

/login本身确实有一些动画:

login.animation.ts

import {
  sequence, trigger, stagger, animate, style, group, query as q, transition, keyframes, animateChild,
  state
} from '@angular/animations';
const query = (s,a,o={optional:true})=>q(s,a,o);

export const listAnimation = trigger('listAnimation', [
  transition(':enter, :leave', [
    query('.container', style({opacity: 0}), {optional: true}),
    query('.container', stagger('300ms', [
      animate('1s ease-in', keyframes([
        style({opacity: 0, transform: 'translateY(-75%)', offset: 0}),
        style({opacity: .5, transform: 'translateY(35px)', offset: 0.3}),
        style({opacity: 1, transform: 'translateY(0)', offset: 1.0})
      ]))]), {optional: true})    
  ])
]);

login.component.ts

import {Component, OnInit} from '@angular/core';
import {FormBuilder, Validators} from '@angular/forms';
import {HttpClient} from '@angular/common/http';
import {AuthenticationService} from '../../service/authentication.service';
import {Router} from '@angular/router';
import {NGXLogger} from 'ngx-logger';
import {listAnimation} from './login.animation';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css'],
  animations: [
    listAnimation
  ],
  host: {
    '[@listAnimation]': ''
  }
})
export class LoginComponent implements OnInit {

  public loginForm = this.formBuilder.group({
    username: [null, Validators.required],
    email: [],
    password: [null, Validators.required],
    passwordConfirm: [null, Validators.required]
  });

  constructor(private formBuilder: FormBuilder, private http: HttpClient,
              private router: Router, private logger: NGXLogger,
              private authenticationService: AuthenticationService) { }

  ngOnInit(): void {
    if (AuthenticationService.isLoggedIn()) {
      this.logger.debug('Already logged in. Goto /home.');
      this.router.navigate(['/home']);
    }
  }

  onSubmit(): void {   
    this.onLoginSuccess();
  }

  onCancel(): void {
    this.router.navigate(['/']);
  }

  private onLoginSuccess(): void {
    this.router.navigate(['/home']);
  }
}

我希望/home等到/login完成。

router.animation.ts 中,我有第一个示例中看到的动画以及第二个示例中的建议transition('route1 => route2', animations)

import {
  sequence, trigger, stagger, animate, style, group, query as q, transition, keyframes, animateChild,
  state
} from '@angular/animations';
import {listAnimation} from './component/login/login.animation';
const query = (s,a,o={optional:true})=>q(s,a,o);

export const routerTransition = trigger('routerTransition', [
  transition('* => *', [
    query(':leave', animateChild()),          
    query(':enter', animateChild())
  ]),

  transition('login => home', listAnimation)
]);

一切正常除了这个事实,/home不等待。当/login执行动画时,/home会立即弹出并混乱场景。

显然我错过了一些东西 - 为了使这项工作,我还需要添加什么?

使用CanDeactivate

扩展 login.component.html ,以便我可以收听动画事件:

  <form [formGroup]="loginForm" (ngSubmit)="onSubmit()" [@listAnimation]="3"
        (@listAnimation.start)="animationStart($event)"
        (@listAnimation.done)="animationDone($event)">

以及 login.component.cs

animationStart() {
  console.log('START');
}

animationDone() {
  console.log('END');
}

canDeactivate(): Observable<boolean> {
  console.log('login.component.ts canDeactivate()');
  return this.animationsDoneSource.asObservable();
}

问题是动画根本没有被执行。

1 个答案:

答案 0 :(得分:0)

如果您希望在继续导航之前完成组件中的所有动画,则应实施CanDeactivate后卫。向所有动画完成后发出的组件添加observable(您可以收听所有动画的.done事件),并在CanActivate后卫中使用它。

<强> login.component.ts

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css'],
  animations: [
    listAnimation
  ],
  host: {
    '[@listAnimation]': ''
  }
})
export class LoginComponent implements OnInit {
  private animationsDoneSource = new Subject<boolean>();

  @HostListener('@listAnimation.done') onDone() {
     this.animationsDoneSource.next();
     this.animationsDoneSuorce.complete();
  }

  canDeactivate(): Observable<boolean> {
    return this.animationsDoneSource.asObservable();
  }
}

<强> login.guard.ts

@Injectable()
export class LoginCanDeactivateGuard implements CanDeactivate<LoginComponent> {

  canDeactivate: Observable<boolean>(
    component: LoginComponent,
  ): Observable<boolean> {
    return component.canDeactivate();
  }
}

<强>登录-routing.module.ts

const routes: Routes = [
  {
    path: 'login',
    component: LoginComponent,
    canDeactivate: [LoginCanDeactivateGuard],
  },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
  providers: [LoginCanDeactivateGuard],
})
export class LoginRoutingModule {}