【问题标题】:Angular - How to avoid initial load animation with queryAngular - 如何使用查询避免初始加载动画
【发布时间】:2020-11-13 00:58:38
【问题描述】:

我正在使用 Angular 10(但问题应该与 Angular 2+ 相同)

我有一个特定页面需要query('.xxx') 在页面加载/卸载时为多个 DOM 元素设置动画。

我想在页面加载/卸载时应用这些动画,除非这是第一次加载(用户访问网站时的第一次页面查看)。

我尝试了很多东西:

  • 父视图上的动画
  • 子视图上的动画
  • 具有特定状态的子视图上的动画(不起作用,因为页面转换是在状态更改之前执行的)
  • 使用特殊的:enter 在首次加载时禁用动画

我可以通过特定的页面更改触发器来获得它,例如 home => pageAxxx => pageA,但我不想列出所有可能性......我的想法是让它与 * <=> * 或至少 @ 987654327@:)

没有得到预期的结果...我认为这是一个常见的情况,有人可以帮我实现吗?

我做了一个 stackblitz 来展示这个想法:https://stackblitz.com/edit/angular-animation-avoid-first?file=src/app/page-a.component.ts

切换主页 pageA 应该触发动画,但 pageA 上的初始加载不应该...

这里我贴出简单的示例代码:

app.component.ts

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { animate, animateChild, query, style, transition, trigger } from '@angular/animations';

@Component({
  selector: 'my-app',
  template: `<main [@routeAnimations]="prepareRoute(outlet)">
              <router-outlet #outlet="outlet"></router-outlet>
            </main>`,
  styleUrls: [ './app.component.css' ],
  animations: [
    trigger('routeAnimations', [
      transition(':enter', []), // to try disabling first animation
      transition('* <=> *', [
        query(':leave', animateChild(), { optional: true }),
        query(':enter', animateChild(), { optional: true }),
      ]),
    ])
  ]
})
export class AppComponent  {
  public prepareRoute(outlet: RouterOutlet) {
    return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
  }
}

home.component.ts

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-home',
  template: `<h1>THIS IS HOME</h1><a [routerLink]="['/']">Page A</a>`,
  styles: []
})
export class HomeComponent  {
}

page-a.component.ts

import { Component, HostBinding } from '@angular/core';
import { Router } from '@angular/router';
import { animate, stagger, style, transition, query, trigger } from '@angular/animations';

@Component({
  selector: 'app-page-a',
  template: '<div class="red">ELEMENT</div><button (click)="changePage()">Change Page</button>',
  styles: ['div {width: 200px;height: 100px;background: #f00}'],
  animations: [
    trigger('animation', [
      transition(':enter', [
        query('.red', [
          style({opacity: 0, transform: 'translateY(-100px)'}),
          animate('500ms cubic-bezier(0.35, 0, 0.25, 1)', style({ opacity: 1, transform: 'none' }))
        ])
      ]),
      transition(':leave', [
        query('.red', [
          animate('500ms cubic-bezier(0.35, 0, 0.25, 1)', style({ opacity: 0, transform: 'translateY(-100px)' }))
        ])
      ])
    ]),
  ]
})
export class PageAComponent {
  
  @HostBinding('@animation')
  public animation;

  public constructor(private router: Router) {}

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

谢谢! :)

【问题讨论】:

  • 我认为您可以研究动画构建器,该构建器将引用页面范围的服务,其中包含信息是否是首次加载并构建适当的动画
  • 为什么不直接使用 cookie,然后从 JS 中读取。也可以使用服务器端和会话。假设您可以使用 HTML5,您也可以使用本地存储。

标签: angular animation triggers


【解决方案1】:

没有办法用简单的动画 api 来实现。我可以向您建议的是检测当前正在发生的导航顺序,如果是第一个则禁用所有动画。
组件:

routeLoadNumber$ = this.router.events.pipe(
    filter(evt => evt instanceof NavigationEnd),
    scan((a)=> a + 1, 0)
  );

constructor(private router: Router) {}

html

<main [@routeAnimations]="prepareRoute(outlet)" [@.disabled]="(routeLoadNumber$ | async)==1">

【讨论】:

  • 我会试试 stackblitz ;你能向我解释为什么“no-op”(又名空:enter)不会禁用子动画吗?这是路由 void => 页面,这就是我要禁用的动画
  • 您可以删除整个“路由”动画,并且组件内部的 :enter 动画仍将运行。不相关
  • 我认为是相关的,因为在官方文档上,说父动画在子组件动画上是领先的;所以禁用 :enter from parent 应该禁用 :enter from child
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-03
  • 2018-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多