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
还分别匹配和的表达式值1
(0
但不匹配,和其他真假值)
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', ...}),
其实这个作用是为了本盒子计算出当前盒子的高度, 从而实现收起动画的过渡
决定自己的高度的是你的态度,而不是你的才能
记得我们是终身初学者和学习者
总有一天我也能成为大佬