Angular動畫

Angular動畫基於W3C的Web Animations標準。不在Angular Core中了。css

組件裏面定義一個或多個觸發器trigger,每一個觸發器有一系列的狀態和過渡效果來實現。html

動畫其實就是從一個狀態過渡到另外一個狀態。狀態自己包含形狀,顏色,大小等。css3

核心是State和Transition。web

State就是定義每一幀狀態npm

Transition是定義一幀到下一幀如何過渡。數組

transition中定義animation,Animate規定了具體怎樣過渡,好比時間,過渡的速度等。Animate有多個重載形式。app

1、例子

先安裝動畫庫ide

npm i --save @angular/animations

導入modulesvg

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
imports: [
...
BrowserAnimationsModule, //放在最後導入
],

定義一個寬度100的黑色正方形。函數

.square{
    width: 100px;
    height: 100px;
    background-color:black;
    align-items: center;
}

在animations元數據中定義一個觸發器,觸發器名字叫square。html的響應元素中[@square]是動畫的觸發器的名字。這個變量或者函數在某一狀況下改變元素的狀態。

<div class="square" [@square]="squareState" (click)="onClick()">
</div>

觸發器有2個重要組成State和Transition。

State定義狀態,在不一樣的狀態下應用不一樣的樣式。經過style把一些css樣式應用於實現動畫的元素,定義好某一幀的顏色,大小,位置。

Transition負責在不一樣狀態切換時候作怎樣的變換,定義如何遷移狀態,如何過渡。

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

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"],
  animations: [
    trigger('square', [
      state('green', style({ 'background-color': 'green','height':'100px','transform':'translateX(0)'  })),
      state('red', style({ 'background-color': 'red','height':'50px' ,'transform':'translateX(100%)'})),
      transition('green=>red', animate('.2s 1s')),//動畫持續的時間,延遲多久開始
      transition('red=>green', animate(1000)),
    ])
  ]
})
export class AppComponent {
  squareState:string;

  onClick(){
    this.squareState = this.squareState ==='red'?'green':'red';
  }
} 

2、緩動函數

動畫執行時候的速度,使其看起來更加真實。

由於不是全部的動畫都是勻速的,能夠先加速後減速。

例如:皮球下落,先是越調越快,撞到地上後回彈最終才又碰到地板。

例子:

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"],
  animations: [
    trigger('square', [
      state('green', style({ 'background-color': 'green','height':'100px','transform':'translateY(-100%)'  })),
      state('red', style({ 'background-color': 'red','height':'100px' ,'transform':'translateY(100%)'})),
      transition('green=>red', animate('.8s ease-in')),
      transition('red=>green', animate('.8s ease-out')),
    ])
  ]
})

能夠在一個網站看到動畫的速度

easings.net

 

能夠參考:

css3中變形與動畫(二)

css3中變形與動畫(三)

3、關鍵幀

不是全部的cubic-bezier函數都能在css動畫中獲得支持,能夠經過關鍵幀來實現。

keyframes是一個數組,裏面定義每一幀的樣式。

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"],
  animations: [
    trigger('square', [
      state('green', style({ 'background-color': 'green','height':'100px','transform':'translateY(-100%)'  })),
      state('red', style({ 'background-color': 'red','height':'100px' ,'transform':'translateY(100%)'})),
      transition('green=>red', animate('.8s ease-in')),
      transition('red=>green', animate(5000, keyframes([
        style({transform:'translateY(100%)'}),
        style({transform:'translateY(98%)'}),
        style({transform:'translateY(95%)'}),
        style({transform:'translateY(90%)'}),
        style({transform:'translateY(80%)'}),
        style({transform:'translateY(60%)'}),
        style({transform:'translateY(30%)'}),
        style({transform:'translateY(0)'}),
        style({transform:'translateY(-10%)'}),
        style({transform:'translateY(-5%)'}),
        style({transform:'translateY(-2%)'}),
        style({transform:'translateY(0)'}),
        style({transform:'translateY(10%)'}),
        style({transform:'translateY(15%)'}),
        style({transform:'translateY(-15%)'}),
        style({transform:'translateY(-40%)'}),
        style({transform:'translateY(-80%)'}),
        style({transform:'translateY(-90%)'}),
        style({transform:'translateY(-95%)'})
      ])))
    ])
  ]
})

4、實際應用

把動畫分離出來,不要和組件強耦合。

新建一個文件夾animate放全部的動畫文件。

一、card相關的動畫——綁定到宿主

新建一個card.animate.ts放card相關的動畫。

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

export const cardAnim = trigger('card',[
    state('out',style({transform:'scale(1)','box-shadow':'none'})),
    state('hover',style({transform:'scale(1.1)','box-shadow':'3px 3px 5px 6px #ccc'})),
    transition('out => hover',animate('200ms ease-in')),
    transition('hover => out',animate('200ms ease-out'))
]);

在project-item裏使用動畫。

一、從@angular/core裏導入HostBinding。

@HostBinding('@card') cardState = 'out';
把變量cardState綁定到@card屬性上去。
至關於組件加上@card屬性<app-project-item [@card]="cardState" >

二、引入另一個HostListener

監聽鼠標enter和leave的事件

  @HostListener('mouseenter', ['$event.target'])
  onMouseEnter(target) {
    this.cardState = 'hover';
  }

  @HostListener('mouseleave', ['$event.target'])
  onMouseLeave(target) {
    this.cardState = 'out';
  }

 

import { Component, OnInit, Input, EventEmitter, Output ,HostBinding ,HostListener} from '@angular/core';
import { cardAnim } from '../../animate/card.animate'

@Component({
  selector: 'app-project-item',
  templateUrl: './project-item.component.html',
  styleUrls: ['./project-item.component.scss'],
  animations:[
    cardAnim
  ]
})
export class ProjectItemComponent implements OnInit {

  @Input() item;
  @Output() onInvite = new EventEmitter<void>();
  @Output() onEdit = new EventEmitter<void>();
  @Output() onDelete = new EventEmitter<void>();
  @HostBinding('@card') cardState = 'out';

  constructor() { }

  ngOnInit() {
  }

  @HostListener('mouseenter')
  onmouseenter(){
    this.cardState = 'hover'
  }

  @HostListener('mouseleave')
  onmouseleave(){
    this.cardState = 'out'
  }

  onInviteClick() {
    this.onInvite.emit();
  }
  onEditClick() {
    this.onEdit.emit();
  }
  onDeleteClick(){
this.onDelete.emit();
  }
}
View Code

 

二、task相關的動畫——綁定到部分元素

不是組件自己的動畫,而是組件中一部分元素的動畫。

新建一個item.animate.ts放task相關的動畫

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

export const itemAnim = trigger('item',[
    state('in',style({'border-left-width':'3px'})),
    state('out',style({'border-left-width':'8px'})),
    transition('in => out',animate('200ms ease-in')),
    transition('out => in',animate('200ms ease-out'))
]);

在test-item中使用

import { Component, OnInit, Input, EventEmitter, Output, HostListener } from '@angular/core';
import {itemAnim} from '../../animate/item.animate';

@Component({
  selector: 'app-task-item',
  templateUrl: './task-item.component.html',
  styleUrls: ['./task-item.component.scss'],
  animations:[
    itemAnim
  ]
})
export class TaskItemComponent implements OnInit {

  @Input() item;
  @Input() avatar: string;
  @Output() taskClick = new EventEmitter<void>();
  widerPriority = 'in';

  constructor() { }

  ngOnInit() {
    this.avatar = this.item.owner ? this.item.owner.avatar : 'unassigned';
  }

  @HostListener('mouseenter')
  onmouseenter(){
    this.widerPriority='out';
  }
  @HostListener('mouseleave')
  onmouseleave(){
    this.widerPriority='in';
  }

  onItemClick() {
    this.taskClick.emit();
  }
  onCheckBoxClick(event: Event): void {
    event.stopPropagation();
  }

}
View Code

在模版中用

<mat-list-item class="container"
[@item]="widerPriority">
<mat-list-item class="container" 
[@item]="widerPriority"
[ngClass]="{
  'priority-normal':item.priority===3,
  'priority-important':item.priority===2,
  'priority-emergency':item.priority===1
}"
  (click)=onItemClick()>
  <mat-checkbox [checked]="item.completed" class="status" (click)="onCheckBoxClick($event)"> </mat-checkbox>
  <div class="content" mat-line [ngClass]="{'completed':item.completed}">
    <span [matTooltip]="item.desc">{{item.desc}}</span>
  </div>
  <div class="bottom-bar" mat-line>
    <span class="due-date" *ngIf="item.dueDate">
      {{item.dueDate | date:"yy-MM-dd"}}
    </span>
    <mat-icon *ngIf="item.reminder">
      alarm
    </mat-icon>
  </div>
  <mat-icon [svgIcon]="avatar" mat-list-avatar class="avatar">

  </mat-icon>
</mat-list-item>
View Code

效果

相關文章
相關標籤/搜索