Angular动画


动机

现代Web组件经常使用动画。级联样式表(CSS)为开发人员提供了创建令人印象深刻的动画的工具。使用CSS可以实现属性转换,唯一命名的动画,多部分关键帧。由于CSS,动画可能性是无穷无尽的。

在现代Web应用程序中,动画集中了用户的注意力。良好的动画旨在以令人满意的,富有成效的方式引导用户的注意力。动画不应该对用户造成烦扰。

动画以动作的形式提供反馈。它们向用户显示应用程序正在主动处理其请求。当应用程序必须加载时,像可见按钮按下或加载器这样简单的东西会吸引用户的注意力。

动画在Angular的案例中继续变得越来越重要。 Google在推广Material Design理念的同时开发了Angular。它鼓励简洁的用户界面(UI),并辅以动画用户反馈。它使Web应用程序感觉有点活泼,使用起来很有趣。

Angular社区开发了一个名为Material2的核心小部件库。该项目为Angular添加了各种小部件模块。其中大多数都以动画为特色。为了理解它们的工作原理,本文建议在阅读之前研究CSS动画。

角度动画是CSS原生提供的框架的简化版本。 CSS是Web浏览器中出现的Angular动画的核心技术。但CSS超出了本文的范围。是时候正面处理Angular动画了。

设置动画

在制作动画之前, BrowserAnimationsModule必须包含在根模块的imports数组中。它可以从@angular/platform-browser/animations 。此NgModule可确保动画适用于给定平台。本文假定每个示例的标准Web浏览器。

角度动画在@Component元数据中声明。 @Component装饰一个类,将其区分为Angular的一个组件。其元数据包含组件配置,包括animations: []字段。此字段中的每个数组元素表示动画触发器( AnimationTriggerMetadata )。

动画通过装饰器的元数据独占于其主机组件。动画只能在主机组件的模板中使用。动画不会继承到组件的子项。有一个简单的解决方法。

您始终可以创建一个导出数组的单独文件。任何组件类都可以从其主机文件的顶部导入该数组。然后,导入的数组标记将进入组件的动画元数据。对其动画元数据中需要相同数组的任何其他组件重复此过程。

内容投影允许您将动画应用于组件A的内容DOM(文档对象模型)。包装此内容的组件B DOM可以将内容投影到其自己的模板中。一旦它发生,组件A的动画不会否定。组件B通过内容投影结合A的动画。

好。您知道如何设置动画以及在何处声明动画。实施是下一步。

动画方法

角度动画使用一系列可从@angular/animations导入的方法调用。 @Component动画数组的每个元素都以单个方法开头。它的参数解析为一系列高阶方法调用。以下列表显示了用于构建Angular动画的一些方法。

  • trigger(selector: string, AnimationMetadata[])

返回AnimationTriggerMetadata

  • state(data: string, AnimationStyleMetadata, options?: object)

返回AnimationStateMetadata

  • style(CSSKeyValues: object)

返回AnimationStyleMetadata

  • animate(timing: string|number, AnimationStyleMetadata|KeyframesMetadata)

返回AnimationAnimateMetadata

  • transition(stateChange: string, AnimationMetadata|AnimationMetadata[], options?: object)

返回AnimationTransitionMetadata

trigger(selector:string,AnimationMetadata [])

trigger(...)方法在动画数组中封装了一个动画元素。

方法的第一个参数selector: string匹配[@selector]成员属性。它的作用类似于组件模板中的属性指令。它实质上是通过属性选择器将动画元素连接到模板。

第二个参数是一个包含适用动画方法列表的数组。 trigger(...)将它完全保存在一个阵列中。

state(data:string,AnimationStyleMetadata,options?:object)

state(...)方法定义动画的最终状态。它在动画结束后将一个CSS属性列表应用于目标元素。这就是动画元素的CSS与动画的分辨率相匹配。

第一个参数匹配绑定到动画绑定的数据的值。也就是说,模板中[@selector]绑定的值与state(...)第一个参数匹配。数据的值决定了最终状态。值的改变决定了动画的手段(见transition(...) )。

第二个参数承载适用于动画后元素的CSS样式。样式通过调用style(...)传入,并将所需样式作为对象传递给其参数。

选项列表可选地占用第三个参数。除非另有说明,否则默认state(...)选项应保持不变。

style(CSSKeyValues:object)

您可能已经在上一个列表中多次注意到AnimationStyleMetadatastyle(...)组件返回这种确切类型的元数据。无论何种CSS样式应用, style(...)方法都必须调用。包含CSS样式的对象代表其参数。

当然,CSS中可动画的样式会延续到Angular style(...)方法中。当然,使用Angular动画突然可能无法实现CSS。

animate(timing:string | number,AnimationStyleMetadata | AnimationKeyframesMetadata)

animate(...)函数接受一个计时表达式作为其第一个参数。此参数会对方法的动画进行计时,调整和/或延迟。此参数接受数字或字符串表达式。

animate(...)的第二个参数是保证动画的CSS属性。这采用了返回AnimationStyleMetadatastyle(...)方法的形式。将animate(...)视为启动动画的方法。

一系列关键帧也可以应用于第二个参数。关键帧是一个更高级的选项,本文稍后将对此进行说明。关键帧区分动画的各个部分。

animate(...)可能不会收到第二个参数。在这种情况下,方法的动画计时仅适用于state(...)方法中反映的CSS。触发器的state(...)方法中的属性更改将设置动画。

转换(changExpr:string,AnimationMetadata | AnimationMetadata [],options?:object)

animate(...)启动动画时动画transition(...)确定动画启动的动画。

第一个参数包含一种独特的微语法形式。它表示发生的状态变化(或数据变化)。绑定到模板动画绑定的数据( [selector]="value" )确定此表达式。即将发布的标题为“动画状态”的部分将进一步解释这一概念。

transition(...)的第二个参数transition(...)包括AnimationMetadata (由animate(...)返回)。该参数接受AnimationMetadata数组或单个实例。

第一个参数的值与模板中绑定的数据的值匹配( [selector]="value" )。如果发生完美匹配,则参数成功评估。然后第二个参数启动动画以响应第一个的成功。

选项列表可选地占用第三个参数。除非另有说明,否则默认transition(...)选项应保持不变。

动画示例
import { Component, OnInit } from '@angular/core';
 import { trigger, state, style, animate, transition } from '@angular/animations';

 @Component({
  selector: 'app-example',
  template: `
  <h3>Click the button to change its color!</h3>
  <button (click)="toggleIsCorrect()"     // event binding
    [@toggleClick]="isGreen">Toggle Me!</button>  // animation binding
    `,
    animations: [       // metadata array
      trigger('toggleClick', [     // trigger block
      state('true', style({      // final CSS following animation
        backgroundColor: 'green'
      })),
      state('false', style({
        backgroundColor: 'red'
      })),
      transition('true => false', animate('1000ms linear')),  // animation timing
      transition('false => true', animate('1000ms linear'))
    ])
  ]        // end of trigger block
 })
 export class ExampleComponent {
  isGreen: string = 'true';

  toggleIsCorrect() {
    this.isGreen = this.isGreen === 'true' ? 'false' : 'true'; // change in data-bound value
  }
 }

上面的示例在每次单击按钮时执行非常简单的颜色交换。当然,根据animate('1000ms linear') ,颜色以线性渐变快速过渡。动画通过将trigger(...)的第一个参数与[@toggleClick]动画绑定相匹配来绑定到按钮。

绑定绑定到组件类中isGreen的值。此值确定由trigger(...)块内的两个style(...)方法设置的结果颜色。动画绑定是单向的,因此组件类中对isGreen更改会通知模板绑定。也就是说,动画绑定[@toggleClick]

模板中的button元素也有一个绑定到它的click事件。单击该按钮会导致isGreen切换值。这会更改组件类数据。动画绑定会选中它并调用其匹配的trigger(...)方法。 trigger(...)位于组件元数据的动画数组中。触发器调用时会发生两件事。

第一次出现涉及两种state(...)方法。 isGreen的新值与state(...)方法的第一个参数匹配。匹配后, style(...)的CSS样式将应用于动画绑定的主机元素的最终状态。 `最终状态在所有动画后生效。

现在第二次出现。调用动画绑定的数据更改在两个transition(...)方法之间进行比较。其中一个将数据更改与其第一个参数进行匹配。第一次按下按钮导致isGreen从'true'变为'false'('true => false')。这意味着第一个transition(...)方法激活其第二个参数。

对应于成功评估的transition(...)方法的animate(...)函数启动。此方法设置动画颜色渐变的持续时间以及淡入淡出的调步。动画执行,按钮渐变为红色。

点击按钮后,此过程可能会发生任意次。按钮的backgroundColor将以线性淡入淡出在绿色和红色之间循环。

动画状态

transition(...)微语法值得详细解决。 Angular通过评估此语法来确定动画及其时间。存在以下状态转换。他们模拟绑定到动画绑定的数据的更改。

  • 'someValue' => 'anotherValue'

一个动画触发器,绑定数据从'someValue'变为'anotherValue'。

  • 'anotherValue' => 'someValue'

动画触发器,绑定数据从“anotherValue”变为“someValue”。

  • 'someValue' <=> 'anotherValue'

数据从'someValue`变为'anotherValue',反之亦然。

还存在void*状态。 void表示组件正在进入或离开DOM。这非常适合进入和退出动画。

  • 'someValue' => void :绑定数据的主机组件离开 DOM

  • void => 'someValue' :绑定数据的主机组件正在进入 DOM

*表示通配符状态。通配符状态可以解释为“任何状态”。这包括void以及对绑定数据的任何其他更改。

关键帧

本文介绍了为Angular应用程序设置动画的基础知识。高级动画技术与这些基础知识并存。将关键帧组合在一起就是这样一种技术。它的灵感来自@keyframes CSS规则。如果您使用过CSS @keyframes ,那么您已经了解了Angular中的关键帧是如何工作的。它只是语法问题

keyframes(...)方法从@angular/animations导入。它传递给animate(...)的第二个参数,而不是典型的AnimationStyleMetadatakeyframes(...)方法接受一个参数作为AnimationStyleMetadata的数组。这也可以称为style(...)方法的数组。

动画的每个关键帧都在keyframes(...)数组内。这些关键帧元素是支持offset属性的style(...)方法。 offset表示动画持续时间中应包含其伴随样式属性的点。它的值从0(动画开始)到1(动画结束)。

import { Component } from '@angular/core';
 import { trigger, state, style, animate, transition, keyframes } from '@angular/animations';

 @Component({
  selector: 'app-example',
  styles: [
    `.ball {
      position: relative;
      background-color: black;
      border-radius: 50%;
      top: 200px;
      height: 25px;
      width: 25px;
    }`
  ],
  template: `
  <h3>Arcing Ball Animation</h3>
  <button (click)="toggleBounce()">Arc the Ball!</button>
  <div [@animateArc]="arc" class="ball"></div>
  `,
  animations: [
    trigger('animateArc', [
      state('true', style({
        left: '400px',
        top: '200px'
      })),
      state('false', style({
        left: '0',
        top: '200px'
      })),
      transition('false => true', animate('1000ms linear', keyframes([
        style({ left: '0',     top: '200px', offset: 0 }),
        style({ left: '200px', top: '100px', offset: 0.50 }),
        style({ left: '400px', top: '200px', offset: 1 })
      ]))),
      transition('true => false', animate('1000ms linear', keyframes([
        style({ left: '400px', top: '200px', offset: 0 }),
        style({ left: '200px', top: '100px', offset: 0.50 }),
        style({ left: '0',     top: '200px', offset: 1 })
      ])))
    ])
  ]
 })
 export class ExampleComponent {
  arc: string = 'false';

  toggleBounce(){
    this.arc = this.arc === 'false' ? 'true' : 'false';
  }
 }

与其他示例相比,上述示例的主要区别在于animate(...)的第二个参数。它现在包含一个托管动画关键帧数组的关键keyframes(...)方法。虽然动画本身也不同,但动画技术是相似的。

单击该按钮会使按钮在屏幕上呈弧形。弧根据keyframes(...)方法的数组元素(关键帧)移动。在动画的中点( offset: 0.50 ),球改变轨迹。当它继续穿过屏幕时,它下降到原始高度。再次单击该按钮可反转动画。

设置position: relative;后, lefttop是可动画的属性position: relative;对于元素。 transform属性可以执行类似的基于移动的动画。 transform是一个广泛但完全可动画的属性。

在偏移0和1之间可以存在任意数量的关键帧。复杂的动画序列采用关键帧的形式。它们是Angular动画中的许多高级技术之一。

主机绑定动画

毫无疑问,您会遇到想要将动画附加到组件本身的HTML元素而不是组件模板中的元素的情况。这需要更多的努力,因为你不能只是进入模板HTML并在那里附加动画。相反,您必须导入HostBinding并使用它。

此方案的最小代码如下所示。我会为上面的代码重复使用相同的动画条件以保持一致性,并且我不会显示任何实际的动画代码,因为您可以轻松地找到上面的代码。

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

 @Component({
 ...
 })
 export class ExampleComponent {
  @HostBinding('@animateArc') get arcAnimation() {
    return this.arc;
  }
 }

动画主机组件背后的想法几乎与从模板中设置元素动画相同,唯一的区别是您无法访问要动画的元素。在声明HostBinding ,您仍然必须传递动画的名称( @animateArc ),并且仍然必须返回动画的当前状态( this.arc )。函数的名称并不重要,因此arcAnimation可以更改为任何内容,只要它不与组件上的现有属性名称冲突,它就可以正常工作。

结论

这涵盖了使用Angular进行动画制作的基础知识。 Angular使用Angular CLI可以非常轻松地设置动画。第一个动画入门只需要一个组件类。请记住,动画范围是组件的模板。如果计划在多个组件中使用过渡数组,请从单独的文件中导出过渡数组。

每个动画实用程序/方法都从@angular/animations导出。他们共同努力,提供一个强大的CSS动画系统。除了本文可以涵盖的内容之外,还有更多方法。

现在您已了解基础知识,请随时浏览以下链接,了解有关Angular动画的更多信息。

更多Angular教程

学习更多Angular教程