angular+ 动画;

最近项目第一阶段已经出来了;开始做收尾优化工作,于是这里准备处理下路由动画的;

然后在官网上看文档,然后自己做个笔记;

angular animation梳理

1.在根模块导入 BrowserAnimationsModule,它能把动画能力引入 Angular 应用的根模块中,并在imports导入声明;
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';


2. 把动画功能函数导入组件文件中:import {
  trigger,
  state,
  style,
  animate,
  transition
  // ...
} from '@angular/animations';

3.在需要使用动画的组件下,添加元数据属性,如:
@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css'],
  animations: [
    // animation triggers go here
  ]
})

// angular 动画基础:
1)样式
// style():指定html部分的动画css样式,样式属性为小驼峰命名;
style({
    opacity: 0.5,
    backgroundColor: 'red'
})

2)样式命名
//    state():创建可命名的css样式,在转换到该命名状态时,应用对应的style样式;state()和style()联用,
//    可以通过切换/引用state名称来切换显示不同样式;
//如:
state('open',style({    // 定义一个名叫 open状态的函数并指定对应的style样式;
    height: '200px',
    opacity: 1,
    backgroundColor: 'yellow'
}))
state('closed', style({ // 定义一个名叫 open状态的函数并指定对应的style样式;
  height: '100px',
  opacity: 0.5,
  backgroundColor: 'green'
}))

3)增加转场动画,使得各个状态样式平滑过渡
//    transition(): 动画转场修饰,通过改变时间和动画顺序让各个state()状态, 第一个参数:定义两个转场state()方向;第二个参数为animate()函数;
//    animate ('duration delay easing'):
//    定义指定的转场时序信息,第一个参数为:持续时间,延迟时间,缓动效果(ease-in(先快后慢),ease-out(先慢后快),ease-in-out(先慢中加速后慢); 第二个参数:单个样式函数style/多步订定义keyframes()
//    如:
 transition ('* => open, closed => open', [ // 定义转场方向,从*(任意)状态到open状态时,使用这个动画,该动画持续1s使得目标透明度为0;多个状态对会共用样式
        animate ('1s',
          style ({ opacity: '0' }),
        ),
      ]), 

4)触发动画
// trigger(): 命名动画,该动画包括了一些state()和transitions等;并绑定到触发动画的元素上
// 当元素上该触发器绑定的值变化时,触发绑定的动画;元素可以同时触发多个触发器,但元素任意时刻只能处于一个状态;
// 如:
    
 animations: [ // 在元数据中,触发openClose触发器,从open转场到close,close=>open;
    trigger('openClose', [
      // ...
      state('open', style({
        height: '200px',
        opacity: 1,
        backgroundColor: 'yellow'
      })),
      state('closed', style({
        height: '100px',
        opacity: 0.5,
        backgroundColor: 'green'
      })),
      transition('open => closed', [
        animate('1s')
      ]),
      transition('closed => open', [
        animate('0.5s')
      ]),
    ]),
  ],


5)将触发器绑定在html的元素上
// <div [@triggerName]="expression">...</div>; // expression的值为state()状态;值变化时匹配相对应的state();
// 如:
<div [@openClose]="isOpen ? 'open' : 'closed'" class="open-close-container">
<p>The box is now {{ isOpen ? 'Open' : 'Closed' }}!</p>
</div>

整体代码如下:

 

 关于导入模块;可以放在根模块下,也可以放在单独模块下;(因为官网的文档是没有目录分级的;而正常项目是有会根据不同项目理念进行不同模块的分级;暂时先这么处理,等我吃透了再回来修改;)

简单目录结构:

 

 

import { Component, OnInit } from '@angular/core';
import { trigger, state, style, animate, transition } from '@angular/animations';
@Component({
  selector: 'app-animation-test',
  templateUrl: './animation-test.component.html',
  styleUrls: ['./animation-test.component.scss'],
  animations: [
    trigger('openClose', [
      state(
        'open',
        style({
          height: '200px',
          opacity: 1,
          backgroundColor: 'yellow'
        })
      ),
      state(
        'close',
        style({
          height: '100px',
          opacity: 0.5,
          backgroundColor: 'red'
        })
      ),
      transition('open => close', [animate('1s')]),
      transition('close => open', [animate('0.5s')])
    // transition('open <=> close', [animate('1s')]) 双箭头可以指定两个状态互相转场 ]) ] }) export class AnimationTestComponent implements OnInit { isOpen
= true; constructor() {} ngOnInit() {} toggle() { this.isOpen = !this.isOpen; } }
<button (click)="toggle()">切换</button>
<div [@openClose]="isOpen ? 'open' : 'close'" class="animation-container">
  <p>hello world</p>
</div>
.animation-container {
  border: 1px solid #dddddd;
  margin-top: 1em;
  padding: 20px 20px 0px 20px;
  color: #000000;
  font-weight: bold;
  font-size: 20px;
}

 

// 如果某个触发器以逻辑型的值作为绑定值,那么就可以使用能与 true 和 false 或 1 和 0 相比较的 transition() 表达式来匹配这个值。

如:
html:
// 触发器openClose绑定值 为 isOpen 状态表达式,其值为逻辑值 true/false;则可以代替响应的'open'/'close'状态

<div [@openClose]="isOpen ? true : false" class="open-close-container">
</div>

// 相对应ts;
// 当isOpen为true时,匹配'open'状态,HTML 元素的高度值为通配符样式 * 或某个默认值。在这种情况下,它会使用此元素开始动画前的现有高度

// 当为false,即'close'时,它的高度会从指定的高度运动到 0,这会让它不可见

animations: [
  trigger('openClose', [
    state('true', style({ height: '*' })), // 
    state('false', style({ height: '0px' })),
    transition('false <=> true', animate(500))
  ])
],

 

 

 

2. 动画转场与触发器进阶


// 特殊转场状态 : 
//    *(通配符): 预定义状态,可匹配任何一个动画状态,常用来定义一些 html元素的起始状态/结束状态的转场动画
如: open => * : 元素从open状态转场变为 任何状态, open <=> close: 两个状态间任意转场 

使用*预定义状态最直接的优点:当存在一对多关系的转场,一个特定状态变化为多个潜在状态,可以简化其操作减少代码,
  如:
    1)常见退回到登录页面,可能存在session失效,
404,loginout等需要跳转到登录页面时,不需要写多个转场到login页面;* => login;     2)还可以作为 非指定状态的补充,当我们在在一个触发器里写了多个转场动画,会按照定义顺序进行匹配(可以理解为switch中default语句);
      当open
=> close 是单独指定特有的转场动画,而open => *可以补充为其他转场动画,所以 * => * 可以作为备用匹配状态; 实例代码html和css 用上面的一样:ts增加一部分: import { Component, OnInit } from '@angular/core'; import { trigger, state, style, animate, transition } from '@angular/animations'; @Component({ selector: 'app-animation-test', animations: [ trigger('openClose', [ state( 'open', style({ height: '200px', opacity: 1, backgroundColor: 'yellow' }) ), state( 'closed', style({ height: '100px', opacity: 0.5, backgroundColor: 'green' }) ), // transition('open => closed', [animate('1s')]), // transition('closed => open', [animate('0.5s')]) transition('* => closed', [animate('1s')]), // transition('* => open', [animate('1s')]) // 带样式的通配符状态,当运行该状态时,转场动画为该状态设定的样式,但转场结束后,会显示需要显示的状态样式,如这里动画结束后会显示open的样式; transition('* => open', [animate('1s', style({ height: '150px', opacity: '0.8', backgroundColor: 'pink' }))]) // transition('open <=> closed', [animate('0.5s')]) 指定状态相互转场动画 // transition('* => *', [animate('1s')]) ]) ], templateUrl: './animation-test.component.html', styleUrls: ['./animation-test.component.scss'] }) export class AnimationTestComponent implements OnInit { isOpen = true; constructor() {} ngOnInit() {} toggle() { this.isOpen = !this.isOpen; } }

 

//    void:空状态;可以作为 进入/离开页面的元素配置转场;(可以理解为 某元素从无到有,从有到无的状态)
//  PS:当html 元素没有在视图中时(常见如删除操作),应用void状态
示例代码: import { Component, Input, Output, EventEmitter } from '@angular/core'; import { trigger, state, style, animate, transition } from '@angular/animations'; import { Hero } from './hero'; @Component({ selector: 'app-hero-list-enter-leave', template: ` <ul class="heroes"> <li *ngFor="let hero of heroes" [@flyInOut]="'in'" (click)="removeHero(hero.id)"> <div class="inner"> <span class="badge">{{ hero.id }}</span> <span>{{ hero.name }}</span> </div> </li> </ul> <p>now state: </p> `, styleUrls: ['./hero-list-page.component.css'], animations: [ trigger('flyInOut', [ // 触发器绑定 flyInOut state('in', style({ transform: 'translateX(0)' })), // 初始绑定值为in状态和样式 transition('void => *', [ // 元素从无到有,元素增加,效果从左侧进入 style({ transform: 'translateX(-100%)' }), // 先在x轴-100%的位置,即试图外 animate(100) // 然后100ms转场变为in 状态;即 0的位置 ]), transition('* => void', [ // 从任意状态到空状态,当该元素被移除,效果从右侧离开 animate(100, style({ transform: 'translateX(100%)' })) // 100ms 位置x轴从 0变为100% ]) ]) ] }) export class HeroListEnterLeaveComponent { @Input() heroes: Hero[]; @Output() remove = new EventEmitter<number>(); removeHero(id: number) { this.remove.emit(id); } } 父组件部分: import { Component } from '@angular/core'; import { HEROES } from './mock-heroes'; @Component({ selector: 'app-hero-list-enter-leave-page', template: ` <section> <h2>Enter/Leave</h2> <app-hero-list-enter-leave [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-enter-leave> </section> ` }) export class HeroListEnterLeavePageComponent { heroes = HEROES.slice(); onRemove(id: number) { this.heroes = this.heroes.filter(hero => hero.id !== id); } }
posted @ 2019-12-20 16:02  抹茶奶盖xh  阅读(616)  评论(0编辑  收藏  举报