angular动画(一)

https://williamjuan027.github.io/angular-animations-explorer/home

注入模块

BrowserAnimationsModule

来个小案例

@Component({
  ...
  animations: [
    trigger('enabledStateChange', [
      state('default', style({opacity: 1})),
      state('disabled', style({opacity: .5, background: '#000'})),
      transition('* => *', animate('1500ms ease-out'))
    ]),
  ]
})

  stateOfElement = 'default';
  toggleMethod() {
    this.stateOfElement = this.stateOfElement === 'default' ? 'disabled' : "default"
  }
<div [@enabledStateChange]="stateOfElement"></div>
<button (click)="toggleMethod()">Click</button>

trigger

trigger(name: string, definitions: AnimationMetadata[]): AnimationTriggerMetadata
参数
name string 一个标识字符串。
definitions AnimationMetadata[] 一个动画定义对象,包含一个数组 state()transition()声明。

创建一个命名的动画触发器

禁用动画

当为 true 时,特殊的动画控件绑定@.disabled绑定会阻止所有动画的渲染。将 @.disabled绑定放在元素上以禁用元素本身的动画,以及元素内的任何内部动画触发器。

@Component({
  selector: 'my-component',
  template: `
    <div [@.disabled]="isDisabled">
      <div [@childAnimation]="exp"></div>
    </div>
  `,
  animations: [
    trigger("childAnimation", [
      // ...
    ])
  ]
})
class MyComponent {
  isDisabled = true;
  exp = '...';
}

另一种方式禁用

 @HostBinding('@.disabled')
  public animationsDisabled = true;

如果 DOM 的某个区域(或整个应用程序)禁用了动画,动画触发器回调仍会触发,但持续时间为零。

state()

附加到元素的触发器中声明动画状态。

      state('default', style({opacity: 1})),

transition()

满足特定指定条件时播放的动画过渡。

  • 第一个参数: 变化表达式
fromState => toState,这表示应该发生转换的动画(a=>b)

transition('open => closed', animate('.5s ease-out', style({ height: 0 }) ))

fromState <=> toState,这表示应该发生转换的动画,(a<=>b)

transition('enabled <=> disabled', animate('1s cubic-bezier(0.8,0.3,0,1)'))
  • :enter/ :leave 当元素显示/隐藏DOM时,出现过渡动画, 产生过渡动画(*ngIf)
  transition(':enter', [
        style({ opacity: 0 , background: '#e53131'}),
        animate('1500ms', style({ opacity: 1, background: '#6b6cc5' }))
      ])

 transition(':leave', [
        style({ opacity: 0 , background: '#e53131'}),
              animate('1500ms', style({opacity: 1, background: '#6b6cc5'}))
      ])
<div [@enabledStateChange]="num" *ngIf="bool">
    内容
</div>
  • :increment/ :decrement,表示当绑定到触发器元素的数值表达式的值增加或减少时,应该发生过渡动画
 transition(':increment', animate('1s ease', keyframes([
        style({ transform: 'scale(1)', offset: 0}),
        style({ transform: 'scale(1.1)', offset: 0.7}),
        style({ transform: 'scale(1)', offset: 1})
      ]))),
      transition(':decrement', animate('1s ease', keyframes([
        style({ transform: 'scale(1)', offset: 0}),
        style({ transform: 'scale(1.1)', offset: 0.7}),
        style({ transform: 'scale(1)', offset: 1})
      ]))),
<div [@enabledStateChange]="num">
    内容
</div>

++num
--num
  • 用逗号分割,来表达多个条件

    transition(':increment, * => enabled, :enter', 
             ... )
    
  • void 元素的缺失

    * 匹配任意状态

    void => * 等价于 :enter dom显示

    * => void 等价于 :leave dom删除

    true并且false还分别匹配和的表达式值10但不匹配,和其他真假值)

query

在序列中动画的当前元素中查找一个或多个内部元素。与 一起使用animate()

query(selector:string,animation: AnimationMetadata | AnimationMetadata[])

selector 类型 string 要查询的元素

query(":enter") 或者 query(":leave") 查询 显示/删除的元素

query(":animating") 查询所有当前动画元素

query("@triggerName") 查询所有动画元素

query("@*"):查询所有包含动画触发器的元素。

query(":self"):将当前元素包含到动画序列中。

多个条件

query(':self, .record:enter, .record:leave, @subTrigger',)

demo

  trigger('queryAnimation', [
      transition('* => goAnimate', [
        // 隐藏内部元素
        query('h1', style({ opacity: 0 })),
        query('.content', style({ opacity: 0 })),

        // 将内部元素动画化,一个接一个
        query('h1', animate(1000, style({ opacity: 1 }))),
        query('.content', animate(1000, style({ opacity: 1 }))),
      ])
    ])
<div [@queryAnimation]="exp">
  <h1>Title</h1>
  <div class="content">
    Blah blah blah
  </div>
</div>
<button (click)="exp='goAnimate'">goAnimate</button>

animate

参数

  • 第一个参数

    type AnimateTimings = {
        duration: number;    持续时间
        delay: number;		延迟时间
        easing: string | null; 
    };
    
  • animate(500):持续时间为 500 毫秒。
  • animate("1s"): 持续时间为 1000 毫秒。
  • animate("100ms 0.5s"): 持续时间为 100 毫秒,延迟为 500 毫秒。
  • animate("5s ease-in"): 持续时间为 5000 毫秒,渐进式。
  • animate("5s 10ms cubic-bezier(.17,.67,.88,.1)"): 持续时间为 5000 毫秒,延迟为 10 毫秒,根据贝塞尔曲线缓动。

group

动画列表组

group([
  animate("1s", style({ background: "black" })),
  animate("2s", style({ color: "white" }))
])

参数的使用
transition(
    '1 => 0',
    [
      style({
        height: '0',
        overflow: 'hidden',
      }),
      group([
        query('@*', animateChild(), { optional: true }),
        animate(
          '{{ duration }}ms {{ delay }}ms {{ ease }}',
          style({
            overflow: 'hidden',
            height: "*",
          }),
        ),
      ]),
    ],
    { params: { duration: 150, delay: '0', ease: 'ease-out' } },
  )

折叠动画

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

/* usage: [@tdCollapse]="{ value: true | false, params: { duration: 500 }}"
 */
export const tdCollapseAnimation: AnimationTriggerMetadata = trigger('tdCollapse', [
  state('0', style({
    height: '*', overflow: '*'
  })),
  state('1', style({
    height: '0', overflow: 'hidden'
  })),
  transition('0 => 1', [
    style({overflow: 'hidden', height: '*'}),
    group([
      query('@*', animateChild(), {optional: true}),
      animate('{{duration}}ms {{delay}}ms {{ease}}', style({height: '0', overflow: 'hidden'})),
    ])
  ], {params: {duration: 150, delay: '0', ease: 'ease-in'}}),
  transition('1 => 0', [
    style({height: '0', overflow: 'hidden'}),
    group([
      query('@*', animateChild(), {optional: true}),
      animate(
        '{{duration}}ms {{delay}}ms {{ease}}',
        style({overflow: 'hidden', height: '*'})
      )
    ])
  ], {params: {duration: 150, delay: '0', ease: 'ease-out'}},)
])

html

<div [@tdCollapse]="{ value: triggerState, params: { duration: 500 }}">
  <div style="background: #c45a5a;height: 400px;"></div>
</div>
<button (click)="triggerState=!triggerState">Click</button>
@Component({
  ...
  animations: [
    tdCollapseAnimation
  ]
})

triggerState: boolean = true;

逻辑解释

{optional:true} 是可选的意思, 就是如果传递参数用传递的参数,没有就用默认的

就是如果[@tdCollapse]="{ value: triggerState, params: { duration: 500 }}" 传入了,就用它的

query('@*', animateChild(), {optional: true}), 这个动画或者子代都遵循这套规则

我们知道来个原生的例子方便我们理解,我们知道我们在使用折腾动画需要确认一个高度, 或者使用js动画,计算子代的高度,从而产生过渡的效果

.yl-fb-hide {
  transition: max-height .3s;
  max-height: 0;
  overflow: hidden;
}

.yl-fb-show {
  overflow: auto;
  max-height: 1000px;
  animation: hide-scroll .3s backwards;
}
@keyframes hide-scroll {
  from{
    max-height: 0;
    overflow:hidden;
  }
  to{
    max-height: 1000px;
    overflow:hidden;
  }
}
  transition('0 => 1', [
    style({overflow: 'hidden', height: '*'}),
    group([
      query('@*', animateChild(), {optional: true}),
      animate('{{duration}}ms {{delay}}ms {{ease}}', style({height: '0', overflow: 'hidden'})),
    ])
  ], {params: {duration: 150, delay: '0', ease: 'ease-in'}}),

可能我们疑惑0 => 1 中为啥要在默认设置 style({overflow: 'hidden', ...}),

其实这个作用是为了本盒子计算出当前盒子的高度, 从而实现收起动画的过渡

posted @ 2022-03-13 15:24  猫神甜辣酱  阅读(105)  评论(0编辑  收藏  举报