使用指令在Angular 8中制作动画的更好方法



UPDATE:找到了一个比我自己编写代码更好的替代方案。请参阅下面的答案。

我正在使用Angular的浏览器动画制作一个网络应用程序的动画。为了在用户向下滚动页面时为对象设置动画,我想我会创建一个指令,该指令可以调用DOM中的像素参考点,并使用窗口服务来确定用户向下滚动了页面的距离。当用户开始向下滚动页面超过某个像素宽度时,我使用相同的窗口服务来淡化我们的导航栏。

我遇到麻烦的地方是从我的动画指令中发出事件。我想将此事件与我试图制作动画的单个元素上的局部变量联系起来

<div [appAnimateLocation]="200" [@slideFromLeft]="vendmfg" (showAnimation)="showAnimation($event, 'vendmfg')" class="container-fluid">
<h6>Content to Animate</h6>
</div>

目前,代码的工作方式是将一些像素传递给我的指令。然后,该指令确定用户何时滚动以满足某些条件(在这种情况下,div的顶部比屏幕底部高200px(,然后应该返回true或false。然后,一个组件方法激发并显式地将一个属性设置为true。如果此属性为true,则可以激发slideFromLeft动画。

我的问题是,有没有一种方法可以在我想要设置动画的每个元素上设置一个局部变量,而不必在组件上设置显式属性?我说的是像这样的东西(或者至少能起到这样作用的东西(

<div [appAnimateLocation]="200" [@slideFromLeft]="var" (showAnimation)="let var as $event" class="container-fluid">
<h6>Content to Animate</h6>
</div>

这可能吗?或者有没有更好的方法可以做到这一点,而我却忽略了这一点?这样,我就可以重复div的动画部分,而不必执行以下操作(我目前正在执行的操作(:

<div [appAnimateLocation]="200" [@slideFromLeft]="vendmfg" (showAnimation)="showAnimation($event, 'vendmfg')" class="container-fluid">
<h6>Content to Animate</h6>
</div>
<div [appAnimateLocation]="200" [@slideFromLeft]="anotherVar" (showAnimation)="showAnimation($event, 'anotherVar')" class="container-fluid">
<h6>More Content to Animate</h6>
</div>

我的文件如下:animations.directive.ts

import {Directive, ElementRef, EventEmitter, HostListener, Inject, Input, Output} from '@angular/core';
import {DOCUMENT} from '@angular/common';
import {WINDOW} from './window.service';
@Directive({
selector: '[appAnimateLocation]'
})
export class AppAnimateLocation {
@Output() showAnimation = new EventEmitter();
constructor(
private el: ElementRef,
@Inject(DOCUMENT) private document: Document,
@Inject(WINDOW) private window: Window
){}
@Input('appAnimateLocation') offset: number;
@HostListener('window:scroll', []) onWindowScroll() {
const screen = window.screen.availHeight;
const scrollPosition = window.pageYOffset;
const componentPosition = this.el.nativeElement.offsetTop;
if (screen + scrollPosition >= componentPosition + this.offset) {
this.showAnimation.emit(true);
} else {
this.showAnimation.emit(false);
}
}
}

动画.ts

import {animate, state, style, transition, trigger} from '@angular/animations';
export let fade =
trigger('fade', [
state('void', style({opacity: 0})),
state('false', style({opacity: 0})),
transition(':enter', [
animate(1500)
]),
transition('false => true', [
animate(1500)
])
]);

windows.service

import { isPlatformBrowser } from '@angular/common';
import { ClassProvider, FactoryProvider, InjectionToken, PLATFORM_ID } from '@angular/core';
/* Create a new injection token for injecting the window into a component. */
export const WINDOW = new InjectionToken('WindowToken');
/* Define abstract class for obtaining reference to the global window object. */
export abstract class WindowRef {
get nativeWindow(): Window | Object {
throw new Error('Not implemented.');
}
}
/* Define class that implements the abstract class and returns the native window object. */
export class BrowserWindowRef extends WindowRef {
constructor() {
super();
}
get nativeWindow(): Window | Object {
return window;
}
}
/* Create an factory function that returns the native window object. */
export function windowFactory(browserWindowRef: BrowserWindowRef, platformId: Object): Window | Object {
if (isPlatformBrowser(platformId)) {
return browserWindowRef.nativeWindow;
}
return new Object();
}
/* Create a injectable provider for the WindowRef token that uses the BrowserWindowRef class. */
export const browserWindowProvider: ClassProvider = {
provide: WindowRef,
useClass: BrowserWindowRef
};
/* Create an injectable provider that uses the windowFactory function for returning the native window object. */
export const windowProvider: FactoryProvider = {
provide: WINDOW,
useFactory: windowFactory,
deps: [ WindowRef, PLATFORM_ID ]
};
/* Create an array of providers. */
export const WINDOW_PROVIDERS = [
browserWindowProvider,
windowProvider
];

最后是我的组件

import {Component, OnInit} from '@angular/core';
import {Router} from '@angular/router';
import {fade, slideFromLeft, slideFromRight} from '../animations';
@Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css'],
animations: [
fade,
slideFromRight,
slideFromLeft,
]
})
export class HomePageComponent implements OnInit {
constructor(
private router: Router
) { }
vendmfg = false;
ngOnInit() {
}
showAnimation(event, el: string){
if(event === true) {
if (el === 'vendmfg') {
this.vendmfg = true;
} 
}
}
}

非常感谢您的帮助或建议。

当我继续研究这个问题,并试图找出如何在向上滚动页面时设置动画时,我遇到了Lucio Francisco的这个stackblitz,它以一种更简洁的方式完成了我试图做的事情。由这篇Medium文章解释。我希望这能帮助到任何一个刚接触动画的人。

最新更新