简体   繁体   中英

Angular 9 animations when in viewport

I want to bring in animations to my project, specifically for <section> and some headings ( h1, h2, h3 ). I have tried a couple of options; one by using Angular animations and one using animate.css .

Both these works as epected, but now I would like to only animate when a <section> is currently in view (for the first time).

At first I tried https://www.npmjs.com/package/ng2-animate-on-scroll , but I was unable to get it to work. Even with animate.scss .

Then I tried: https://scrollrevealjs.org/ by using https://www.npmjs.com/package/ngx-scrollreveal . This did work, but I could only get it to use the cubic-bezier(0.25, 0.1, 0.25, 1) . Nothing else seemed to work and I would like to have all the functionality that is available in animate.css or at least fadeInUp , fadeInLeft and fadeInRight

Then I tried: https://github.com/Epenance/ngx-animate-in#readme which again, works and is the best so far because it uses angular animations, but isn't supported in IE at all, so that is no good.

So, my question is: Is there a better way of doing this? Ideally I would like to use angular animations when scrolling content into view and I would like to have control on which animation to use. Is this possible and has anything done or used anything that might help?

In the end, used some old code I had an merged it with the ngx-animate directive to come up with this:

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

@Directive({
  selector: '[sxpAnimate]',
})
export class AnimateDirective {
  @Input() animateInAnimation: AnimationMetadata | AnimationMetadata[];
  @HostListener('window:scroll', ['$event']) // for window scroll events
  onScroll() {
    this.animate();
  }

  private animating: boolean;
  private player: AnimationPlayer;
  private defaults: any = {
    offset: 0,
  };

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

  ngOnInit() {
    this.initialize();
    this.animate();
  }

  private initialize(): void {
    let animation: AnimationFactory;

    if (
      this.animateInAnimation !== null &&
      this.animateInAnimation !== undefined
    ) {
      animation = this.animationBuilder.build(this.animateInAnimation);
    } else {
      animation = this.animationBuilder.build([
        style({ opacity: 0, transform: 'translateX(-100px)' }),
        animate(
          '1200ms cubic-bezier(0.35, 0, 0.25, 1)',
          style({ opacity: 1, transform: 'translateX(0)' })
        ),
      ]);
    }

    this.player = animation.create(this.el.nativeElement);
    this.player.init();
  }

  private animate(): void {
    const inView = this.isInViewport();

    if (!inView) this.animating = false;
    if (!inView || this.animating) return;

    this.player.play();
    this.animating = true;
  }

  private isInViewport(): boolean {
    const bounding = this.el.nativeElement.getBoundingClientRect();

    let top =
      bounding.top -
      (window.innerHeight || document.documentElement.clientHeight);
    let bottom = bounding.top + bounding.height + this.defaults.offset;

    return top < 0 && bottom > 0;
  }
}

Seems to work as I want; so I will build on this:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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