Лучший способ Animate в Angular 8 с использованием директив - PullRequest
0 голосов
/ 07 ноября 2019

ОБНОВЛЕНИЕ: нашел намного лучшую альтернативу тому, что я пытался кодировать сам. См. Ответ ниже.

Я использую Angular's Browser Animations для анимации веб-приложения. В попытке анимировать объекты, когда пользователь прокручивает страницу вниз, я решил создать директиву, которая могла бы вызывать 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);
    }

  }
}

animation.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;
      } 
    }
  }

}

Любая помощь или совет с благодарностью.

1 Ответ

0 голосов
/ 13 ноября 2019

Продолжая разбираться с этим и пытаясь понять, как анимировать при прокрутке назад страницу, я натолкнулся на этот стек-блиц , созданный Лучио Франциско, который делает то, что я пытался сделать вспособ более краткий. Объяснено этой Средней статьей. Я надеюсь, что это поможет любому, кто плохо знаком с анимацией.

...