angular2 学习笔记 ( animation 动画 )
2020-06-03 原生 animation api vs angular animation vs css animation
refer :
https://css-tricks.com/myth-busting-css-animations-vs-javascript/
https://www.w3cplus.com/animation/web-animation-api-from-entry-to-the-top.html
https://stackoverflow.com/questions/49628726/what-is-the-purpose-of-angular-animations
虽然说 angular 基于原生来实现,但使用上还是有蛮大区别的。
ng 没有 fill mode, 只能通过 style 来实现最终停留点. (注意: fill mode 会锁死 element 无法在 set style 哦, 通常不会是我们要的,所以我认为 ng 的做法更合理一点)
原生有 play, reverve 等功能,这些是 ng 没有的.
ng 不需要定义初始 style 而且有 * 可以代表当前的 style value, 原生则必须自己去获取所有 value 而且一定要 set start 和 end 2 个,缺一不可.
ng 可以做 group, stagger, query 等等等...原生没有
所以总体来说我还是觉得 ng 的 animation 比较好用。
顺便说一下 css animation
css aniamtion 的功能弱很多,因为 aniamtion api 本来就是为了弥补 css aniamtion 不足才诞生的.
refer :
https://angular.io/guide/animations
https://github.com/angular/angular/blob/master/packages/animations/src/animation_metadata.ts
https://github.com/angular/angular/commit/f1a9e3c (router)
angular 的动画建立在一堆的方法上:
1. trigger
触发器, 用来和 dom 交互 <div [@triggerName]="state" ></div>
trigger 负责定义各种 state 和它们之间变化来变化去 transition
trigger('triggerA', [ state('A', style...), state('B', style...), transition('A => B', animate...), transition('B => A', animate...) ])
2. State
angular 的概念是通过改变状态(state)来触发(trigger)动画(animate)
每个状态都定义了最终的样式
state('A', style...)
3. transition
负责定义各种 state 之间错综复杂的转换关系
transition('A => B', animate...) transition('A <=> B', animate...) transition('* => *', animate...) * is whatever transition(':enter', animate...) transition(':leave', animate...) transition('* => void', animate...) void表示无, whatever to null 也等于 :leave transition((fromState, toState) => boolean, animate...) 还可以写方法判断哦 transition('A => B',[style,animate]) style 也可以放进来哦. transition('A => B',[animate,animate]) 数组 animate 会按序执行和 transition('A => B', sequence([animate,animate])) 是一样的 transition('A => B',group(animate,animate)) 不想按序执行可以使用 group
到这里可以看出一个基本的流程
[@triggerName]="state" 监听了 state 的变化
一但变化发生触发器就查找匹配的 transition 然后执行 animate. 就这样简单
4. Style
就是定义 css 啦
style({ display : 'none' })
5. animate
具体的动画定义
animate("5s 10ms cubic-bezier(.17,.67,.88,.1)", style(...))
duration= 5second
delay=10ms
easing= cubic-bezier (ease-out 等等 css 有的都可以放)
最后加上 style 就可以动画了咯
animate("5s", keyframes([ style({opacity: 0, offset: 0}), style({opacity: 1, offset: 0.3}) ]))
如果你想完全掌握节奏可以使用 keyframes + offset 做定义, offset 0.3 是百分比
6.group
就是把多个 animate 组合起来并发执行.
group(animate,animate)
7.keyframes
上面说了
8.sequence
按顺序一个接一个执行, 和 group 刚好打对台, 一个 step by step, 另一个是并发
sequence(animate,animate)
9.useAnimation
animate是可以封装的. 使用 animation 方法
let fadeAnimation = animation([ style({ opacity: '{{ start }}' }), animate('{{ time }}', style({ opacity: '{{ end }}')) ], { params: { time: '1000ms', start: 0, end: 1 }});
然后在任何想使用 animate 的地方改用 useAnimation
useAnimation(fadeAnimation, { params: { time: '2s', start: 1, end: 0 } })
10.query
任何你想使用 animate 的地方都可以使用 query
animate 会施法在当前的 element 上, 而通过 query 你可以施法在 element 的 child 上
query 支持 css 选择器的语法,还有一些 angular 特别的定义语法.
query('css-selector',[animate...])
- Querying for newly inserted/removed elements using `query(":enter")`/`query(":leave")`
这里有个神技
<div [@listAnimation]="items.length"> <div *ngFor="let item of items"> {{ item }} </div> </div>
通过 items.length 配上下面的 transition * => * + query child 就可以实现 items 在插入和移除时的动画了.
transition('* => *', [ query(':leave', [ stagger(100, [ animate.. ]) ]), query(':enter', [ stagger(100, [ animate.. ]) ]) ])
- Querying all currently animating elements using `query(":animating")`
- Querying elements that contain an animation trigger using `query("@triggerName")`
- Querying all elements that contain an animation triggers using `query("@*")`
- Including the current element into the animation sequence using `query(":self")`
11.stagger
stagger 是配合 query 来使用的, 它的作用是当 query select 出很多 element 时,你希望它们不要并发, 而是隔着一个间隔时间.
query('css-selector',[stagger(100,[animate])])
比如 select 出 2 个 element, 一个触发动画先,另一个则会等间隔 100ms 后才触发.
12.animateChild
animateChild 是一个 manual trigger 概念
<div [@parentAnimation]="exp"> <div [@childAnimation]="exp"> one </div> </div>
angular 说, 当 parent trigger 触发后,child trigger by default 是不会被触发的 (不过我试了会 /.\)
而我们可以在 parent trigger 中通过 query('@child',[animateChild()]) 来手动触发 child trigger.
这个在做 router animate 时会用到哦.
router animation 实现 https://github.com/angular/angular/commit/f1a9e3c
其实也是依据上面这些方法来做的. 主要用了 parent, child, query, enter, leave, animateChild 这些概念.