13

我有一个DirectiveI can put on elements 来检查相关元素的当前滚动位置。

看起来像这样:

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

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

我想要这样的东西:

import { myScrollAnimation } from './animations';

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

我怎样才能在指令中实现这一点?

使用:角度4.0.0-rc.4

4

5 回答 5

25

Angular 4.2 带来了很多动画改进。其中之一是 AnimationBuilder,它允许程序化动画构建。

您只需要在指令中注入 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 })),
    ];
  }
}
于 2018-03-23T00:07:15.410 回答
11

根据对benshabatnoam的回答中提到的问题的响应,我使用了一些解决方法。

指令实际上只是没有模板的组件。[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>
于 2018-03-22T16:01:34.900 回答
3

正如我在您问题的评论部分中提到的那样。

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

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

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

// when logic is true
this.animationTrigger = this.classThatTriggersAnimation;
于 2017-07-27T18:20:30.467 回答
2

这是 Angular 的 git 存储库中的一个未解决问题(至于今天 - 28/08/17)。请投票赞成这个问题,以便向开发人员施加压力以更快地发布这个问题。

于 2017-08-28T15:07:07.247 回答
2

开始了。适合微小的动画。

我直接使用AnimationPlayer + AnimationBuilder => 无需人为地向前切换状态 + 向后触发动画。受此片段启发并进一步简化。

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: '*' })), 
];
于 2020-10-15T14:51:46.387 回答