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

时间:2017-03-18 18:23:57

标签: javascript angular typescript angular4

我有Directive我可以放置元素来检查相关元素的当前滚动位置。

看起来像这样:

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

每当该位置满足某个阈值时,我希望该元素使用动画显示在屏幕上。我知道,对于Component我可以附加animations属性以及host属性中的一些设置来激活动画。

我想要这样的事情:

import { myScrollAnimation } from './animations';

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

如何在指令中实现这一目标?

使用:Angular 4.0.0-rc.4

5 个答案:

答案 0 :(得分:8)

Angular 4.2 brought in a lot of animation improvements. One of them is AnimationBuilder, which allows for programmatic animation construction.

You just need to inject AnimationBuilder in your directive, and you can turn any AnimationMetadata into working animation.

@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 })),
    ];
  }
}

答案 1 :(得分:4)

我根据对{benshabatnoam的答案中提到的问题的this回复使用了一些解决方法。

指令实际上只是没有模板的组件。您可以使用属性选择器(例如:[selector])并制作模板<ng-content></ng-content>来创建与指令相同的组件。

因此,您可以创建一个'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 = '';
}

并像使用任何指令一样使用它:

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

答案 2 :(得分:2)

正如我在你的问题评论部分所述。

您可以在父组件中进行动画配置。 然后该指令只在满足阈值时在其主机上添加一个类。

在你的指令中,你可以有类似的东西:

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

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

答案 3 :(得分:2)

这是有角度的git reposetory的open issue(今天 - 2017年8月28日)。请对这个问题进行投票,以便向开发人员施加压力,使其更快地发布。

答案 4 :(得分:1)

在这里,我们走。适用于小型动画。

我直接使用AnimationPlayer + AnimationBuilder =>无需人为地将状态向前+向后切换即可触发动画。受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) { }
}

在您的模板中:

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

在您的组件类中:

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: '*' })), 
];