Angular Animation

       Angular Animation简单来说 就是状态和状态之间的转场效果。每一种状态对应一种样式(style)。Angular Animation指导从一种状态的样式过渡到另一种状态的样式效果过程。

Angular Animation和咱们Android里面的属性动画类似。

       如果想在我们的应用中使用动画,有一个前提条件,得先引入BrowserAnimationsModule模块。建议在app module里面引入。

       开始部分,我们先贴出文章里面涉及到的所有例子的下载的地址:https://github.com/tuacy/AngularAnimation

       例子都是非常简单的例子,咱也是个初学者。高深的例子咱也写不出来。

一、Angular Animation里面各个函数解释

       Angular Animation动画使用起来不难,在加上咱之前有Android动画的经验。Angular Animation看起来就更加的简单了。

1.1. trigger触发器

        trigger触发器,trigger将根据提供的triggerName值创建一个动画触发器。在模板中使用[@triggerName]语法来把它附加到一个或多个元素上去。可以简单的理解为这个时候就把元素和触发器对应的动画绑定起来了。

       比如如下的代码我们就定义了一个名字为flyInOut的一个触发器。

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

@Component({
    selector: 'app-keyframes-animation',
    templateUrl: './keyframes-animation.component.html',
    styleUrls: ['./keyframes-animation.component.css'],
    animations: [
        trigger('flyInOut', [
            state('in', style({transform: 'translateX(0)'})),
            // keyframes多阶段动画(任何状态切换的时候都使用该动画)
            transition('* => *', [
                animate(1000, keyframes([
                    style({opacity: 0, transform: 'translateX(-100%)', offset: 0}),
                    // 多往右边移除一点
                    style({opacity: 1, transform: 'translateX(50%)', offset: 0.5}),
                    style({opacity: 1, transform: 'translateX(0)', offset: 1.0})
                ]))
            ])
        ])
    ]
})
export class KeyframesAnimationComponent implements OnInit {

    constructor() {
    }

    ngOnInit() {
    }

}

       上面的代码只是定义了一个触发器,但是还没有把触发器和页面上的元素绑定起来(在模板中使用[@triggerName]来绑定),比如如下的代码我们就把div绑定到了这个触发器上。

<br>
<h5>keyframes关键帧多阶段动画</h5>
<br>

<div style="width: 200px; height: 200px;background-color: #67ee38" [@flyInOut]></div>
<br>

1.2. state状态

       state状态,通过这个state函数来定义每个状态最终的样式(动画开始时候的样子和动画结束之后的样子);想要动画动起来需要通过改变状态(state)来触发(trigger)动画(animate)。

上面咱们贴了trigger触发器时候的代码实例,在trigger函数里面有state函数,定义了一个 in的状态对应的样式为transform: 'translateX(0)'。

1.3. transition转换

       transition负责定义各种 state之间的转换关系,并且定义state转换的时候使用什么的样的动画来完成。

       这里我们着重要讲下状态装换在Angular Animation中是怎么定义的状态之间装换的。

trigger('animationState', [
            // stateA 状态最终样式
            state('stateA', style({
                backgroundColor: '#67ee38',
                transform: 'scale(1)'
            })),
            // stateB 状态最终样式
            state('stateB', style({
                backgroundColor: '#4a302c',
                transform: 'scale(1.1)'
            })),
            // stateA 到 stateB 状态动画
            transition('stateA => stateB', animate('500ms ease-in')),
            // stateB 到 stateA 状态动画
            transition('stateB => stateA', animate('500ms ease-out'))
        ]),

       上面的代码trigger里面有两个transition。分别定义了'stateA => stateB'和'stateB => stateA'的状态变化。Angular Animation里面两个状态之间的装换就是通过 '状态 => 状态' 这样的表达式来定义的。在Angular Animation里面有两种特殊的状态; ×、void状态。其中×状态匹配任何状态,void状态表示元素没有被附加到视图时候的状态。

       讲到状态,那咱们还得提下元素的入场和出场动画的添加了。比如下面的实例。我们定义了入场和出场的动画。

    animations: [
        trigger('flyInOut', [
            state('in', style({opacity: 1, transform: 'translateX(0) scale(1)'})),
            // 进场动画
            transition('void => *', [
                style({opacity: 0, transform: 'translateX(-100%) scale(0)'}),
                animate(500)
            ]),
            // 出场动画
            transition('* => void', [
                animate(500, style({opacity: 0, transform: 'translateX(100%) scale(0)'}))
            ])
        ])
    ]

应该比较好理解吧,void => * 表示入场。* => void 表示出场。当然入场你也可以用:enter代替,出场可以用:leave代替。

animation_enter.gif

1.4. style样式

       Angular Animation动画的过程就是在改变元素的CSS样式或者CSS3 transform 属性。style函数可以出现在state函数,transition函数,animate函数中。

       假设有这样的需求,动画结束但是我们不想保留动画结束点的那个状态。实现过程查看如下代码。

 // 动画结束不保留状态
        trigger('animationStateNoSave', [
            transition('stateA => stateB', [
                style({
                    backgroundColor: '#4a302c',
                    transform: 'scale(1.1)'
                }),
                animate('1000ms ease-in', style({
                    backgroundColor: '#67ee38',
                    transform: 'scale(1)'
                }))
            ]),
            transition('stateB => stateA', [
                style({
                    backgroundColor: '#67ee38',
                    transform: 'scale(1)'
                }),
                animate('1000ms ease-in', style({
                    backgroundColor: '#4a302c',
                    transform: 'scale(1.1)'
                }))
            ])
        ])

注意这里我们没有通过state函数来指定状态对应的style。

       Angular Animation支持的CSS样式如下:

css属性的名字 animation style 对应名字 解释
background-color backgroundColor 设置元素的背景颜色
background-position backgroundPosition 设置背景图像的起始位置
border-bottom-color borderBottomColor 设置下边框的颜色
border-bottom-width borderBottomWidth 设置下边框的宽度
border-left-color borderLeftColor 属性设置元素的左边框的颜色
border-left-width borderLeftWidth 属性设置元素的左边框的宽度
border-right-color borderRightColor 属性设置元素的右边框的颜色
border-right-width borderRightWidth 属性设置元素的右边框的宽度
border-spacing borderSpacing 设置相邻单元格的边框间的距离
border-top-color borderTopColor 属性设置元素的上边框的颜色
border-top-width borderTopWidth 属性设置元素的上边框的宽度
bottom bottom 定元素的底部边缘
clip clip 剪裁绝对定位元素
color color 规定文本的颜色
font-size fontSize 设置字体的尺寸
font-weight fontWeight 设置文本的粗细
height height 设置元素的高度
left left 设置元素的左边缘
letter-spacing letterSpacing 设置字符间的空白(字符间距)
line-height lineHeight 设置行间的距离(行高)
margin-bottom marginBottom 设置元素的下外边距
margin-left marginLeft 设置元素的左外边距
margin-right marginRight 设置元素的右外边距
margin-top marginTop 设置元素的上外边距
max-height maxHeight 设置元素的最大高度
max-width maxWidth 设置元素的最大宽度
min-height minWidth 设置元素的最小高度
min-width minWidth 设置元素的最小宽度
opacity opacity 设置元素的不透明级别
outline-color outlineColor 设置元素整个轮廓的颜色
outline-width outlineWidth 设置元素整个轮廓的宽度
padding-bottom paddingBottom 设置元素的下内边距
padding-left paddingLeft 设置元素的左内边距
padding-right paddingRight 设置元素的右内边距
padding-top paddingTop 设置元素的上内边距
right right 规定元素的右边缘
text-indent textIndent 首行文本的缩进
text-shadow textShadow 向文本设置阴影
top top 规定元素的顶部边缘
visibility visibility 规定元素是否可见
width width 元素的宽度
word-spacing wordSpacing 设置单词间的空白
z-index zIndex 设置元素的堆叠顺序

       Angular Animation支持的CSS3
transform 属性如下:

transform 属性 描述
matrix(n,n,n,n,n,n) 2D 转换,使用六个值的矩阵
matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n) 3D 转换,使用 16 个值的 4x4 矩
translate(x,y) 2D 转换
translate3d(x,y,z) 3D 转换。
translateX(x) 转换,只是用X轴
translateY(y) 转换,只是用 Y 轴的值
translateZ(z) 3D 转换,只是用 Z 轴的值。
scale(x,y) 缩放转换
scale3d(x,y,z) 3D 缩放转换。
scaleX(x) 通过设置 X 轴的值来定义缩放转换
scaleY(y) 通过设置 Y 轴的值来定义缩放转换
scaleZ(z) 通过设置 Z 轴的值来定义 3D 缩放转换。
rotate(angle) 2D 旋转,在参数中规定角度
rotate3d(x,y,z,angle) 3D 旋转。
rotateX(angle) 沿着 X 轴的 3D 旋转
rotateY(angle) 沿着 Y 轴的 3D 旋转
rotateZ(angle) 沿着 Z 轴的 3D 旋转
skew(x-angle,y-angle) 沿着 X 和 Y 轴的 2D 倾斜转换
skewX(angle) 沿着 X 轴的 2D 倾斜转换
skewY(angle) 沿着 Y 轴的 2D 倾斜转换
perspective(n) 3D 转换元素定义透视视图

1.5. animate动画

       animate表示具体的动画定义
。定义动画的持续时间,动画延时多长时间执行,动画的缓动函数(https://easings.net/zh-cn)。

1.6. group组

       group是一个动画特定的函数,指定一个并行运行的动画步骤列表。分组动画是当一系列样式必须在不同的开始/结束时间进行动画/关闭时很有用。同时执行多个动画。(多个动画组合在一起同时触发)。比如如下效果图,同时有颜色变化动画和翻转动画执行。

animation_并行动画.gif

1.7. keyframes关键帧

       keyframes描述每个样式条目是如何应用的,以及在什么点动画弧(很像CSS关键帧动画)。相当于把动画分段了。比如如下动画我们通过keyframes实现了动画多往左边移动了一段距离在回到最终位置(当然了你也可以通过缓动函数来实现)。

animation_keyframes.gif

1.8. sequence顺序

       sequence指定逐个运行的动画步骤列表,这个也就是和group特性正好相反,一个同时进行,一个按先后顺序一个一个的进行。

比如下面的例子,进场动画我们就定义了几个动画顺序执行

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

@Component({
    selector: 'app-sequence-animation',
    templateUrl: './sequence-animation.component.html',
    styleUrls: ['./sequence-animation.component.css'],
    animations: [
        trigger('flyInOut', [
            state('in', style({transform: 'rotateX(0) translateX(0)', opacity: 1})),
            // 多个动画同时执行
            transition('void => *', sequence([
                style({
                    opacity: 0,
                }),
                animate('1s ease-in-out', style({
                        opacity: 1,
                    }
                )),
                animate('1s ease-in-out', style({
                        transform: 'rotateX(90deg)',
                    }
                )),
                animate('2s ease', style({
                    transform: 'rotateY(90deg)',
                })),
            ]))
        ])
    ]
})
export class SequenceAnimationComponent implements OnInit {

    constructor() {
    }

    ngOnInit() {
    }

}

animation_顺序动画.gif

1.10. query

       query用于在当前元素中查找(query)一个或多个内部元素在序列中进行动画。把动画作用在子元素上。

import {Component, OnInit} from '@angular/core';
import {animate, query, style, transition, trigger} from '@angular/animations';

@Component({
    selector: 'app-query-animation',
    templateUrl: './query-animation.component.html',
    styleUrls: ['./query-animation.component.css'],
    animations: [
        trigger('queryAnimation', [
            // 入场的时候对子元素采用动画
            transition('* => goAnimate', [
                // hide the inner elements
                query('h1', style({
                    opacity: 0
                })),
                query('.content', style({
                    opacity: 0
                })),
                // 动画作用于内容元素
                query('h1', animate(1000, style({
                    opacity: 1
                }))),
                query('.content', animate(1000, style({
                    opacity: 1
                })))
            ])
        ])
    ]
})
export class QueryAnimationComponent {

}

animation_子元素.gif

1.11. stagger

       stagger需要在query里面使用,stagger的作用在于每个动画发出之后隔多长时间在发下一个动画。比如咱们有这样的需求,ul里面有好多个li。想要一个这样的效果。li的动画一个挨着一个执行。代码如下

        trigger('listAnimation', [
            transition('* => *', [ // each time the binding value changes
                query(':enter', [
                    // 所有子元素入场动画
                    style({opacity: 0}),
                    stagger('0.5s', [
                        animate('0.5s', style({opacity: 1}))
                    ])
                ])
            ])
        ])]

1.12. animateChild

       在angular中,因为每次动画被触发,父动画将始终获得优先权,任何子动画都将被阻止,为了子动画也有动画效果,父动画必须查询每一个包含子动画的元素并用animateChild来运行子动画。animateChild需要和query一起使用。

trigger('parentAnimation', [
            transition('false => true', [
                // 查找parentAnimation对应element里面的header标签执行动画
                query('header', [
                    style({opacity: 0}),
                    animate(500, style({opacity: 1}))
                ]),
                query('@childAnimation', [
                    animateChild()
                ])
            ])
        ]),
        trigger('childAnimation', [
            transition('false => true', [
                style({opacity: 0}),
                animate(500, style({opacity: 1}))
            ])
        ])

1.13. 动画回调

       动画开始的时候有个回调函数,动画结束的时候也有个回调函数。

1.9. animation的封装

       借助useAnimation函数我们可以对动画做一个简单的封装。比如如下的代码我们把封装了两个动画,放在animation.ts文件里面。

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

// 封装动画1
const inAnimation = animation([
    style({
        opacity: '{{ start }}',
        transform: 'translateX(-100%)'
    }),
    animate('{{ time }}',
        style({
            opacity: '{{ end }}',
            transform: 'translateX(0)'
        }))
], {params: {time: '1000ms', start: 0, end: 1}});

// 封装动画2
const outAnimation = animation([
    style({
        opacity: '{{ start }}',
        transform: 'translateX(0)'
    }),
    animate('{{ time }}',
        style({
            opacity: '{{ end }}',
            transform: 'translateX(-100%)'
        }))
], {params: {time: '1000ms', start: 0, end: 1}});


// 如下面我定一个动效用到上面封装的动画
export const routerEnterLeave = trigger('fadel', [
    // 入场
    transition(':enter', [
        useAnimation(inAnimation, {
            params: {
                time: '2s',
                start: 0,
                end: 1
            }
        })
    ]),
    // 出场
    transition(':leave', [
        useAnimation(outAnimation, {
            params: {
                time: '2s',
                start: 1,
                end: 0
            }
        })
    ])
]);


       关于Angular Animation咱们就撤这么多,文章中涉及到的所有例子下载地址https://github.com/tuacy/AngularAnimation。希望能帮到大家。最后还是想强调下最好的文档是官方文档https://v6.angular.live/guide/animations

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容