He estado construyendo un nuevo sitio usando Angular 4 y estoy tratando de recrear un efecto en el que cuando un div se vuelve visible (cuando se desplaza hacia abajo en la pantalla), eso puede desencadenar una animación angular para deslizar el div en forma los lados.
Pude hacer esto en el pasado usando jQuery fuera de Angular 4 pero quiero probar y crear el mismo efecto usando animaciones nativas de Angular 4.
¿Alguien puede darme consejos sobre cómo activar una animación cuando aparece un div (es decir, se desplaza hacia abajo a la parte inferior de la página cuando ingresa a la ventana gráfica?). Ya escribí las animaciones de diapositivas, pero no sé cómo activarlas con un desplazamiento cuando un div se vuelve visible en una fecha posterior en el puerto de visualización.
¡Gracias a todos!
Creé una directiva que emite un evento tan pronto como el elemento está completamente a la vista o su borde superior ha alcanzado el borde superior de la vista.
Aquí hay un plunker: https://embed.plnkr.co/mlez1dXjR87FNBHXq1YM/
Se usa así:
<div (appear)="onAppear()">...</div>Aquí está la directiva:
import { ElementRef, Output, Directive, AfterViewInit, OnDestroy, EventEmitter } from '@angular/core'; import {Observable} from 'rxjs/Observable'; import {Subscription} from 'rxjs/Subscription'; import 'rxjs/add/observable/fromEvent'; import 'rxjs/add/operator/startWith'; @Directive({ selector: '[appear]' }) export class AppearDirective implements AfterViewInit, OnDestroy { @Output() appear: EventEmitter<void>; elementPos: number; elementHeight: number; scrollPos: number; windowHeight: number; subscriptionScroll: Subscription; subscriptionResize: Subscription; constructor(private element: ElementRef){ this.appear = new EventEmitter<void>(); } saveDimensions() { this.elementPos = this.getOffsetTop(this.element.nativeElement); this.elementHeight = this.element.nativeElement.offsetHeight; this.windowHeight = window.innerHeight; } saveScrollPos() { this.scrollPos = window.scrollY; } getOffsetTop(element: any){ let offsetTop = element.offsetTop || 0; if(element.offsetParent){ offsetTop += this.getOffsetTop(element.offsetParent); } return offsetTop; } checkVisibility(){ if(this.isVisible()){ // double check dimensions (due to async loaded contents, eg images) this.saveDimensions(); if(this.isVisible()){ this.unsubscribe(); this.appear.emit(); } } } isVisible(){ return this.scrollPos >= this.elementPos || (this.scrollPos + this.windowHeight) >= (this.elementPos + this.elementHeight); } subscribe(){ this.subscriptionScroll = Observable.fromEvent(window, 'scroll').startWith(null) .subscribe(() => { this.saveScrollPos(); this.checkVisibility(); }); this.subscriptionResize = Observable.fromEvent(window, 'resize').startWith(null) .subscribe(() => { this.saveDimensions(); this.checkVisibility(); }); } unsubscribe(){ if(this.subscriptionScroll){ this.subscriptionScroll.unsubscribe(); } if(this.subscriptionResize){ this.subscriptionResize.unsubscribe(); } } ngAfterViewInit(){ this.subscribe(); } ngOnDestroy(){ this.unsubscribe(); } }La respuesta de Martin Cremer se actualizó para funcionar con las últimas versiones de Rxjs y Angular, espero que esto ayude
import { ElementRef, Output, Directive, AfterViewInit, OnDestroy, EventEmitter } from '@angular/core'; import { Subscription } from 'rxjs'; import { fromEvent } from 'rxjs'; import { startWith } from 'rxjs/operators'; @Directive({ selector: '[appear]' }) export class AppearDirective implements AfterViewInit, OnDestroy { @Output() appear: EventEmitter<void>; elementPos: number; elementHeight: number; scrollPos: number; windowHeight: number; subscriptionScroll: Subscription; subscriptionResize: Subscription; constructor(private element: ElementRef) { this.appear = new EventEmitter<void>(); } saveDimensions() { this.elementPos = this.getOffsetTop(this.element.nativeElement); this.elementHeight = this.element.nativeElement.offsetHeight; this.windowHeight = window.innerHeight; } saveScrollPos() { this.scrollPos = window.scrollY; } getOffsetTop(element: any) { let offsetTop = element.offsetTop || 0; if (element.offsetParent) { offsetTop += this.getOffsetTop(element.offsetParent); } return offsetTop; } checkVisibility() { if (this.isVisible()) { // double check dimensions (due to async loaded contents, eg images) this.saveDimensions(); if (this.isVisible()) { this.unsubscribe(); this.appear.emit(); } } } isVisible() { return this.scrollPos >= this.elementPos || (this.scrollPos + this.windowHeight) >= (this.elementPos + this.elementHeight); } subscribe() { this.subscriptionScroll = fromEvent(window, 'scroll').pipe(startWith(null)) .subscribe(() => { this.saveScrollPos(); this.checkVisibility(); }); this.subscriptionResize = fromEvent(window, 'resize').pipe(startWith(null)) .subscribe(() => { this.saveDimensions(); this.checkVisibility(); }); } unsubscribe() { if (this.subscriptionScroll) { this.subscriptionScroll.unsubscribe(); } if (this.subscriptionResize) { this.subscriptionResize.unsubscribe(); } } ngAfterViewInit() { this.subscribe(); } ngOnDestroy() { this.unsubscribe(); } }Una forma sencilla si lo quieres en un componente específico:
@ViewChild('chatTeaser') chatTeaser: ElementRef; @HostListener('window:scroll') checkScroll() { const scrollPosition = window.pageYOffset + window.innerHeight; if (this.chatTeaser && this.chatTeaser.nativeElement.offsetTop >= scrollPosition) { this.animateAvatars(); } }Y en html:
<div id="chat-teaser" #chatTeaser> Exactamente cuando se desplaza la parte superior del elemento, se llama a la función. Si desea llamar a la función solo cuando el div completo está a la vista, agregue la altura del div a this.chatTeaser.nativeElement.offsetTop .