【问题标题】:How do you create reusable Animations in Angular 2如何在 Angular 2 中创建可重用的动画
【发布时间】:2016-09-13 06:18:51
【问题描述】:

我正在使用动画 API,我想创建一个可重复使用的动画,比如在顶级路由器视图的内容中滑动。我设法通过了时髦的元数据语法(一旦摆脱了使用元数据的疯狂想法,这实际上非常酷)以使动画大部分工作。

   @Component({
      //moduleId: module.id,
      selector: 'album-display',
      templateUrl: './albumDisplay.html',
      animations: [
        trigger('slideIn', [
          state('*', style({
            transform: 'translateX(100%)',
          })),
          state('in', style({
            transform: 'translateX(0)',
          })),
          state('out',   style({
            transform: 'translateX(-100%)',
          })),
          transition('* => in', animate('600ms ease-in')),
          transition('in => out', animate('600ms ease-in'))
        ])
      ]
  })
  export class AlbumDisplay implements OnInit {
      slideInState = 'in';
      ...
  }

然后将其分配给组件中的顶级元素:

  <div  class="container" [@slideIn]="slideInState">

所以这行得通,但我怎样才能使它可重复使用?我不想将这些元数据粘贴到每个视图上。由于这是元数据,我不确定您如何使其可重用。

【问题讨论】:

  • 别忘了输入触发器:export const myTrigger:AnimationEntryMetadata = trigger( ...... 否则你会得到一个构建错误。

标签: angular angular2-animation


【解决方案1】:

一种可能的方法是将动画触发代码放在单独的文件中并将其导出为const变量并在组件中使用它,如下所示。

animations.ts

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

export const slideIn = trigger('slideIn', [
  state('*', style({
    transform: 'translateX(100%)',
  })),
  state('in', style({
    transform: 'translateX(0)',
  })),
  state('out',   style({
    transform: 'translateX(-100%)',
  })),
  transition('* => in', animate('600ms ease-in')),
  transition('in => out', animate('600ms ease-in'))
]);

album-display.component.ts

import { slideIn } from './animations'; // path to your animations.ts file

@Component({
    //moduleId: module.id,
    selector: 'album-display',
    templateUrl: './albumDisplay.html',
    animations: [
      slideIn
    ]
})
export class AlbumDisplay implements OnInit {
    slideInState = 'in';
    ...
}

【讨论】:

  • 谢谢你完美的工作。在最初考虑 WTF 关于这个基于元的时髦实现之后,在使用这种语法创建了一些之后,事实证明为组件创建动画非常容易。
  • 此解决方案将阻止您使用 AOT-Compiling :/
  • 有没有办法使用这个而不手动将[@slideIn]应用于每个元素?就像在 ng1 中一样,所有元素都会自动很好地动画
  • 我知道这是一个老话题,但是关于如何在 AOT 编译中使用它有什么想法吗?
  • 这确实适用于 AOT - 也许一年前它没有,但现在可以
【解决方案2】:

也许有点晚了,但我仍然想为更动态的触发器版本提供答案。

将动画触发代码放在单独的文件中并导出为function

translate.ts

import { AnimationEntryMetadata, trigger, state, style, transition, animate } from '@angular/core';

export function TranslateX( name: string, x: string, duration: number ): AnimationEntryMetadata {
    return trigger( name, [
            state('false', style({ transform: 'translateX(0)' }) ),
            state('true',  style({ transform: 'translateX(' + x + ')' }) ),
            transition('0 => 1', animate( duration + 'ms ease-in')),
            transition('1 => 0', animate( duration + 'ms ease-out')),
        ]);
}

所以,在组件 app.component.ts

import { TranslateX } from './translate';

@Component({
    ...
    templateUrl: './app.component.html',
    animations:   [ 
                    TranslateX( 'trigger1Title','-100%', 200 ),
                    TranslateX( 'trigger2Title','20vw', 700 )
                  ]
    ...
})

在模板app.component.html

...
<div [@trigger1Title]="token1"> ... </div>
<div [@trigger2Title]="token2"> ... </div>
...

您可以使用更多输入数据自定义触发器,例如分隔转换时间等。

【讨论】:

  • 与 AOT 编译一起使用时会失败
  • 只有当构建触发器使用类、枚举或对其他函数进行内部调用时,您的陈述才是正确的。我目前正在使用 Angular 4、TypeScript 2.4.2 并按上述方式编写,一切正常。
  • 如果你使用模板字符串(反引号)而不是使用加号+的传统字符串连接,看起来它会失败@
  • 你是对的,正如你所看到的,在示例中没有使用反引号。
  • @Simon_Weaver 已替换为AnimationTriggerMetadata
【解决方案3】:

Angular 4 中的路由器动画示例

我刚刚使用 Angular 4 自己完成了路由器动画的处理,这里有几个示例动画,用于淡入过渡和滑入/滑出过渡。

查看this post 了解更多详情和现场演示。

Angular 4 滑入/滑出动画

// import the required animation functions from the angular animations module
import { trigger, state, animate, transition, style } from '@angular/animations';
 
export const slideInOutAnimation =
    // trigger name for attaching this animation to an element using the [@triggerName] syntax
    trigger('slideInOutAnimation', [
 
        // end state styles for route container (host)
        state('*', style({
            // the view covers the whole screen with a semi tranparent background
            position: 'fixed',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            backgroundColor: 'rgba(0, 0, 0, 0.8)'
        })),
 
        // route 'enter' transition
        transition(':enter', [
 
            // styles at start of transition
            style({
                // start with the content positioned off the right of the screen,
                // -400% is required instead of -100% because the negative position adds to the width of the element
                right: '-400%',
 
                // start with background opacity set to 0 (invisible)
                backgroundColor: 'rgba(0, 0, 0, 0)'
            }),
 
            // animation and styles at end of transition
            animate('.5s ease-in-out', style({
                // transition the right position to 0 which slides the content into view
                right: 0,
 
                // transition the background opacity to 0.8 to fade it in
                backgroundColor: 'rgba(0, 0, 0, 0.8)'
            }))
        ]),
 
        // route 'leave' transition
        transition(':leave', [
            // animation and styles at end of transition
            animate('.5s ease-in-out', style({
                // transition the right position to -400% which slides the content out of view
                right: '-400%',
 
                // transition the background opacity to 0 to fade it out
                backgroundColor: 'rgba(0, 0, 0, 0)'
            }))
        ])
    ]);

Angular 4 淡入动画

// import the required animation functions from the angular animations module
import { trigger, state, animate, transition, style } from '@angular/animations';
 
export const fadeInAnimation =
    // trigger name for attaching this animation to an element using the [@triggerName] syntax
    trigger('fadeInAnimation', [
 
        // route 'enter' transition
        transition(':enter', [
 
            // css styles at start of transition
            style({ opacity: 0 }),
 
            // animation and styles at end of transition
            animate('.3s', style({ opacity: 1 }))
        ]),
    ]);

附加了过渡的组件

import { Component } from '@angular/core';
 
// import fade in animation
import { fadeInAnimation } from '../_animations/index';
 
@Component({
    moduleId: module.id.toString(),
    templateUrl: 'home.component.html',
 
    // make fade in animation available to this component
    animations: [fadeInAnimation],
 
    // attach the fade in animation to the host (root) element of this component
    host: { '[@fadeInAnimation]': '' }
})
 
export class HomeComponent {
}

【讨论】:

  • 很好的例子。您是否有理由使用 absolute 来移动而不是使用优化得多的 translate?
  • @JJB 是的,当我尝试使用翻译时,我使用负的正确位置来移动表单,同时将背景留在原位以淡出,当我尝试使用翻译时,它会将表单和背景滑出页面。我找不到在“:离开”过渡上为子元素设置动画的方法,否则我会为背景和表单使用单独的 div,而我可以在其中使用翻译。这是我能想出的唯一方法,只使用一个 html 元素就可以淡出背景并在表单中滑动。
【解决方案4】:

正确的解决方案是在指令中支持动画。

事实并非如此,但在 Angular 的 Github 上有一个问题:https://github.com/angular/angular/issues/9947

希望早日解决。

【讨论】:

    【解决方案5】:

    有了一个类,你可以扩展,

    import { trigger, style, state, animate, transition, AnimationMetadata } from "@angular/core";
    export class MyAwesomeAnimations {
    
        /**
         * 
         * @param nameTrigger Name of triggers
         * @param setNewsStates add states for animations
         * @param setNewTransitions add transitions for states
         */
        SetTrigger(nameTrigger: string, setNewsStates?: AnimationMetadata[], setNewTransitions?: AnimationMetadata[]): any {
            let metaData: AnimationMetadata[] = [
                state('*', style({
                    transform: 'translateX(100%)',
                })),
                state('in', style({
                    transform: 'translateX(0)',
                })),
                state('out', style({
                    transform: 'translateX(-100%)',
                })),
                transition('* => in', animate('600ms ease-in')),
                transition('in => out', animate('600ms ease-in'))
            ];
            if (setNewsStates)
                metaData.concat(setNewsStates);
            if (setNewTransitions)
                metaData.concat(setNewTransitions);
    
    
            return trigger(nameTrigger, metaData);
        }
    }
    

    供使用

        @Component({
            selector: "orden-detail-component",
            animations: [new MyAwesomeAnimations().SetTrigger("slideIn")],
            template:"<div  class="container" [@slideIn]="slideInState">"
        })
        export class OrdenDetailComponent {
           slideInState = 'in';
        }
    

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 2016-12-24
      • 2017-11-14
      • 1970-01-01
      • 1970-01-01
      • 2017-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-25
      相关资源
      最近更新 更多