two - ¿Cómo manejar el evento de desplazamiento de ventana en Angular 4?
get element angular 6 (4)
Parece que no puedo capturar el evento de desplazamiento de la ventana. En varios sitios encontré un código similar a este:
@HostListener("window:scroll", [])
onWindowScroll() {
console.log("Scrolling!");
}
Los fragmentos a menudo provienen de la versión 2. Esto parece no funcionar (¿ya?) En Angular 4.2.2. Si reemplazo "window: scroll" con "window: touchmove", por ejemplo, entonces el evento touchmove se maneja bien.
¿Alguien sabe lo que me estoy perdiendo? ¡Muchas gracias!
@PierreDuc gracias por la respuesta.
Como se describe en la sección Mejora del rendimiento de desplazamiento con oyentes pasivos en MDN:
No necesita preocuparse por el valor de pasivo para el evento de desplazamiento básico. Como no se puede cancelar, los oyentes de eventos no pueden bloquear la representación de la página de todos modos.
Por lo que a mí respecta, su respuesta puede simplificarse simplemente pasando true como el tercer parámetro para la función window.addEventListener
No tengo permitido comentar todavía. @PierreDuc su respuesta es acertada, excepto cuando @Robert dijo que el documento no se desplaza. Modifiqué un poco su respuesta para usar el evento enviado por el oyente y luego monitorear el elemento fuente.
ngOnInit() {
window.addEventListener(''scroll'', this.scrollEvent, true);
}
ngOnDestroy() {
window.removeEventListener(''scroll'', this.scrollEvent, true);
}
scrollEvent = (event: any): void => {
const number = event.srcElement.scrollTop;
}
Probablemente su
document
no se esté desplazando, pero sí un
div
dentro.
El evento de desplazamiento solo aparece en la
window
si se llama desde el
document
.
Además, si captura el evento del
document
y llama a algo como
stopPropagation
, no recibirá el evento en la
window
.
Si desea capturar todos los eventos de desplazamiento dentro de su aplicación, que también serán de pequeños contenedores desplazables, debe usar el método
addEventListener
predeterminado con
useCapture
establecido en
true
.
Esto activará el evento cuando baje el
DOM
, en lugar de la etapa de burbuja.
Desafortunadamente, y francamente una gran falta, angular no proporciona una opción para pasar las opciones de escucha del evento, por lo que debe usar
addEventListener
:
export class WindowScrollDirective {
ngOnInit() {
window.addEventListener(''scroll'', this.scroll, true); //third parameter
}
ngOnDestroy() {
window.removeEventListener(''scroll'', this.scroll, true);
}
scroll = (): void => {
//handle your scroll here
//notice the ''odd'' function assignment to a class field
//this is used to be able to remove the event listener
};
}
Ahora, esto no es todo, ya que todos los principales navegadores (excepto IE y Edge, obviamente) han implementado la nueva especificación
addEventListener
, que permite pasar un objeto como
tercer parámetro
.
Con este objeto puede marcar un detector de eventos como
passive
.
Se recomienda hacer esto en un evento que se activa mucho tiempo, lo que puede interferir con el rendimiento de la interfaz de usuario, como el evento de desplazamiento.
Para implementar esto, primero debe verificar si el navegador actual admite esta función.
En mozilla.org, han publicado un método
passiveSupported
, con el que puede verificar la compatibilidad del navegador.
Sin embargo, solo puede usar esto cuando esté seguro de que no va a usar
event.preventDefault()
Antes de mostrarle cómo hacerlo, hay otra característica de rendimiento que se le ocurre.
Para evitar que se ejecute la detección de cambios (se llama a
DoCheck
cada vez que ocurre algo asíncrono dentro de la zona. Como un disparo de evento), debe ejecutar su detector de eventos fuera de la zona y solo ingresarlo cuando sea realmente necesario.
Entonces, combinemos todas estas cosas:
export class WindowScrollDirective {
private eventOptions: boolean|{capture?: boolean, passive?: boolean};
constructor(private ngZone: NgZone) {}
ngOnInit() {
if (passiveSupported()) { //use the implementation on mozilla
this._eventOptions = {
capture: true,
passive: true
};
} else {
this.eventOptions = true;
}
this.ngZone.runOutsideAngular(() => {
window.addEventListener(''scroll'', this.scroll, <any>this.eventOptions);
});
}
ngOnDestroy() {
window.removeEventListener(''scroll'', this.scroll, <any>this.eventOptions);
//unfortunately the compiler doesn''t know yet about this object, so cast to any
}
scroll = (): void => {
if (somethingMajorHasHappenedTimeToTellAngular) {
this.ngZone.run(() => {
this.tellAngular();
});
}
};
}
Si está utilizando material angular , puede hacer esto:
import { ScrollDispatchModule } from ''@angular/cdk/scrolling'';
En ts:
import { ScrollDispatcher } from ''@angular/cdk/scrolling'';
constructor(private scrollDispatcher: ScrollDispatcher) {
this.scrollDispatcher.scrolled().subscribe(x => console.log(''I am scrolling''));
}
Y en plantilla:
<div cdkScrollable>
<div *ngFor="let one of manyToScrollThru">
{{one}}
</div>
</div>
Referencia: https://material.angular.io/cdk/scrolling/overview