简体   繁体   English

Angular 2 - 如何在指令上设置动画?

[英]Angular 2 - How to set animations on a Directive?

I have a Directive I can put on elements that checks the current scroll position of the element in question.我有一个Directive我可以放在元素上,检查相关元素的当前滚动位置。

Looks like this:看起来像这样:

@Directive({
    selector: '[my-scroll-animation]'
})

Whenever the position satifies a certain treshold, I want the element to appear on screen using an animation.每当位置满足某个阈值时,我希望元素使用动画出现在屏幕上。 I know that for a Component I can attach an animations property along with some settings in the host property to activate the animation.我知道对于一个Component我可以附加一个animations属性以及host属性中的一些设置来激活动画。

I would like something like this:我想要这样的东西:

import { myScrollAnimation } from './animations';

@Directive({
    selector: '[my-scroll-animation]'
    animations: [myScrollAnimation] // <- not possible?
})

How can I achieve this in a Directive?我怎样才能在指令中实现这一点?

Using: Angular 4.0.0-rc.4使用:Angular 4.0.0-rc.4

Angular 4.2 brought in a lot of animation improvements. Angular 4.2 带来了很多动画改进。 One of them is AnimationBuilder, which allows for programmatic animation construction.其中之一是 AnimationBuilder,它允许程序化的动画构建。

You just need to inject AnimationBuilder in your directive, and you can turn any AnimationMetadata into working animation.您只需要在指令中注入 AnimationBuilder,就可以将任何 AnimationMetadata 转换为工作动画。

@Directive({
  selector: '[zetFadeInOut]',
})
export class FadeInOutDirective {
  player: AnimationPlayer;

  @Input()
  set show(show: boolean) {
    if (this.player) {
      this.player.destroy();
    }

    const metadata = show ? this.fadeIn() : this.fadeOut();

    const factory = this.builder.build(metadata);
    const player = factory.create(this.el.nativeElement);

    player.play();
  }

  constructor(private builder: AnimationBuilder, private el: ElementRef) {}

  private fadeIn(): AnimationMetadata[] {
    return [
      style({ opacity: 0 }),
      animate('400ms ease-in', style({ opacity: 1 })),
    ];
  }

  private fadeOut(): AnimationMetadata[] {
    return [
      style({ opacity: '*' }),
      animate('400ms ease-in', style({ opacity: 0 })),
    ];
  }
}

I used a bit of a workaround based on this response to the issue mentioned in benshabatnoam's answer.我有点用一种变通方法的基础上这一响应benshabatnoam的回答中提到的问题。

Directives are actually just components without templates.指令实际上只是没有模板的组件。 You can create a component that acts identical to a directive by using a attribute selector ( eg: [selector] ) and making the template: <ng-content></ng-content> .您可以通过使用属性选择器(例如: [selector] )并制作模板: <ng-content></ng-content>来创建一个与指令相同的组件。

As a result, you can create a 'foux-directive' component like so:因此,您可以创建一个“foux-directive”组件,如下所示:

@Component({
    selector: '[fadeInAnimation]',
    animations: [
        trigger('fadeIn', [
             transition(':enter', [
                 style({opacity:'0'}),
                 animate(200, style({opacity:'1'}))
             ])
        ])
    ], 
    template: `<ng-content></ng-content>`,
})
export class FadeInDirective {
    @HostBinding('@fadeIn') trigger = '';
}

and use it like you would use any directive:并像使用任何指令一样使用它:

<div fadeInAnimation> something I want to animate </div>

As I mentioned in your question's comment section.正如我在您问题的评论部分中提到的。

You can have the animation configuration in your parent component.您可以在父组件中进行动画配置。 Then the directive just adds a class on its host when it satisfies the threshold.然后该指令在满足阈值时在其主机上添加一个类。

In your directive, you can have something like:在您的指令中,您可以有以下内容:

@Input() classThatTriggersAnimation = "do-animation";
@HostBinding('[@nameOfAnimation]') animationTrigger = ""; 

// when logic is true
this.animationTrigger = this.classThatTriggersAnimation;

This is an open issue (as for today - 28/08/17) in Angular's git repository.这是 Angular 的 git 存储库中的一个悬而未决的问题(截至今天 - 28/08/17)。 Please vote up this issue in order to put pressure on the developers to release this faster.请对此问题进行投票,以便向开发人员施加压力以加快发布速度。

Here we go.开始了。 Good for tiny animations.适合小动画。

I am directly using AnimationPlayer + AnimationBuilder => No need to artificially toggle a state forth + back to trigger the animation.我直接使用AnimationPlayer + AnimationBuilder => 不需要人为地前后切换状态来触发动画。 Inspired by and further reduced from this snippet .受此片段的启发并进一步简化。

import { Directive, Input, HostListener } from '@angular/core';
import { ElementRef } from '@angular/core';
import {
    AnimationPlayer,
    AnimationBuilder
} from '@angular/animations';

@Directive({
    selector: '[clickAnimation]',
})
export class ClickAnimationDirective {
    private player: AnimationPlayer;

    @Input() clickAnimation: any;

    @HostListener('click', ['$event'])
    onClick() {
        // sanitize just in case
        if (this.player) { this.player.destroy(); }

        const factory = this.builder.build(this.clickAnimation);
        const player = factory.create(this.el.nativeElement);

        // ensure back-to-original
        player.onDone(() => { player.reset(); });
        player.play();
    }

    constructor(private builder: AnimationBuilder, private el: ElementRef) { }
}

In your template:在您的模板中:

<app-button
    [clickAnimation]="trafficLight"
    ...

In your component class:在您的组件类中:

public trafficLight: AnimationMetadata[] = [
    style({ borderColor: 'red' }),
    animate('400ms ease-in', style({ borderColor: 'yellow' })),
    animate('400ms ease-in', style({ borderColor: 'cyan' })),
    //alternative way to ensure back to original
    // animate('400ms ease-in', style({ borderColor: '*' })), 
];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM