Как добавить анимацию между маршрутами вопросов в Angular? - PullRequest
0 голосов
/ 24 апреля 2020

Я работаю над приложением викторины в Angular 9 и пытаюсь добавить анимацию между маршрутами вопросов, например: question / 1, question / 2, et c. Прямо сейчас анимация работает в начале первого вопроса и между переходом между последним вопросом и результатами. Кажется, не работает, когда я нажимаю предыдущую или следующую кнопку в DIQuizComponent. Не уверен как go насчет починки. Пожалуйста, не могли бы вы увидеть мой код ниже.

router-animations.ts :

import { trigger, transition, group, query, style, animate } from '@angular/animations';

export class RouterAnimations {
  static routeSlide =
    trigger('routeSlide', [
      transition('* <=> *', [
        group([
          query(':enter', [
            style({transform: 'translateX({{offsetEnter}}%)'}),
            animate('0.4s ease-in-out', style({transform: 'translateX(0%)'}))
          ], {optional: true}),
          query(':leave', [
            style({transform: 'translateX(0%)'}),
            animate('0.4s ease-in-out', style({transform: 'translateX({{offsetLeave}}%)'}))
          ], {optional: true}),
        ])
      ]),
    ]);
}

quiz-routing.module.ts :

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { IntroductionComponent } from '../containers/introduction/introduction.component';
import { DependencyInjectionQuizComponent } from '../containers/dependency-injection-quiz/dependency-injection-quiz.component';
import { ResultsComponent } from '../containers/results/results.component';

const routes: Routes = [
  { path: '', redirectTo: 'intro', pathMatch: 'full' },
  { path: 'intro', component: IntroductionComponent, pathMatch: 'full' },
  { path: 'question', component: DependencyInjectionQuizComponent, pathMatch: 'full' },
  { path: 'question/:questionIndex', component: DependencyInjectionQuizComponent, pathMatch: 'full' },
  { path: 'results', component: ResultsComponent, pathMatch: 'full' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class QuizRoutingModule {}

app.component. html:

<main class="container grid-sm">
  <router-outlet></router-outlet>
</main>

route-reuse-стратегии.ts :

import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';

import { DependencyInjectionQuizComponent } from '../containers/dependency-injection-quiz/dependency-injection-quiz.component';


export class CustomReuseStrategy implements RouteReuseStrategy {
  handlers: {[key: string]: DetachedRouteHandle} = {};

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return false;
  }

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    this.handlers[route.routeConfig.path] = null;
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return !!route.routeConfig && !!this.handlers[route.routeConfig.path];
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    if (!route.routeConfig) {
      return null;
    }
    return this.handlers[route.routeConfig.path];
  }

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return curr.component !== DependencyInjectionQuizComponent;
  }
}

внутри di-quiz.component.ts :

  private setupRouting() {
    this.prev$ = this.questionChange$
      .pipe(
        map(questionIndex => questionIndex === 0 ? questionIndex : questionIndex - 1),
        share()
      );
    this.next$ = this.questionChange$
      .pipe(
        map(questionIndex => questionIndex === this.questions.length - 1 ? questionIndex : questionIndex + 1),
        share()
      );

    this.routeTrigger$ = this.questionChange$
      .pipe(
        startWith(0),
        pairwise(),
        map(([prev, curr]) => ({
          value: curr,
          params: {
            offsetEnter: prev > curr ? 100 : -100,
            offsetLeave: prev > curr ? -100 : 100
          }
        })),
      );
  }

в di-quiz.component. html шаблон:

<mat-card [@routeSlide]="routeTrigger$ | async">
...
  <mat-card-footer>
    <section class="paging">
      <mat-card-actions>
        <div
          class="prev-question-nav"
          *ngIf="question && questionIndex > 1">
          <button
            type="button"
            mat-raised-button
            (click)="prevQuestion()"
            [routerLink]="prev$ | async"
            [class.disabled]="(questionChange$ | async) === 0">
            <strong>&laquo; Previous</strong>
          </button>
        </div>

        <div
          class="next-question-nav"
          *ngIf="question && questionIndex !== totalQuestions">
          <button
            type="button"
            mat-raised-button
            (click)="nextQuestion()"
            [routerLink]="next$ | async"
            [class.disabled]="(questionChange$ | async) === questions.length - 1">
            <strong>Next &raquo;</strong>
          </button>
        </div>

        <div
          class="show-score-nav"
          *ngIf="question && questionIndex === totalQuestions">
          <button type="button" mat-raised-button (click)="results()"
                  disableRipple="true" class="btn btn-outline-primary">
            <strong>Show Your Score</strong>
          </button>
        </div>
      </mat-card-actions>
    </section>
</mat-card>

questions-routing.service.ts:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class QuestionsRoutingService {
  questionChange$ = new BehaviorSubject<number>(0);
}

1 Ответ

1 голос
/ 27 апреля 2020

Я подготовил небольшую демонстрацию с включенной анимацией перед переходом на новый маршрут. https://stackblitz.com/edit/angular-7uu97i.

Идея состоит в том, что вы запускаете анимацию, ожидая ее завершения. и перейдите к следующему маршруту. Вы можете использовать демо в качестве примера.

Надеюсь, это поможет.

...