No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Infinite Scrolling: evento de scroll

11/20
Recursos

Aportes 26

Preguntas 7

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Passive lo que hace es evitar el llamado de preventDefault() en el caso de que este existiese en la funci贸n llamada por el Listener. En los navegadores que usa la gente normal el valor por defecto es false por lo que no se aplica, pero en el caso de Safari e Internet Explorer el valor por defecto es true. Por lo que supongo que es recomendable ponerle un valor para que el c贸digo se ejecute igual en todos los navegadores.

esta clase la vi mas veces de lo que me gustar铆a admitir

Por lo que entend铆 al leer la documentaci贸n, el tercer par谩metro que se le env铆a al EventListener es opcional y especifica las condiciones en la que se ejecuta el mismo.

addEventListener(type, listener, options);

Existen varias opciones, como use, signal, passive y capture, este 煤ltimo es el que se usa por defecto al colocar un valor booleano, como es el caso. Lo que determina capture es el orden en el que se ejecutan los eventos cuando existen varios que responden a la misma acci贸n. Al estar en false el orden de ejecuci贸n es desde el padre del evento(por ejemplo un bot贸n) a la raiz del 谩rbol (DOM), y en el caso de ser true el orden se invierte, por lo que se priorizan los elementos m谩s cercanos al DOM en orden jer谩rquico. Primero se ejecutan los eventos que tengan capture true(del m谩s grande al m谩s chico) y luego los false (del m谩s chico al m谩s grande).
.
Esta im谩gen me ayudo a entenderlo.

Capture phase = true
Bubbling phase = false (por defecto)
Target Phase = elemento 鈥渕as peque帽o鈥 que escucha al evento

documentaci贸n EventTarget.addEventListener()

A esto se refiere el tercer par谩metro del EventListener: Bubbling y Capturing
En el siguiente link hay una explicaci贸n detalla con ejemplos interactivos LINK

No habia entendido como funcionan y se relacionan los atributos clientHeight, scrollTop y scrollHeight. Leyendo los entendi asi que este es un resumen de como funcionan y se relacionan:
.
1- document.documentElement.clientHeight: Devuelve la altura VISIBLE del elemento documentElement en pixeles incluyendo el padding del elemento pero no el border, ni el margin del elemento ni la barra de dezplazamiento horizontal del navegador.
.
Como clientHeight NO devuelve la altura total de un elemento sino la altura visible del elemento, entonces si el tama帽o de pantalla del dispositivo se reduce o si el tama帽o de la ventana del navegador se reduce entonces la altura visible del elemento tambien se reducira por lo tanto el valor de .clientHeight se reducira y visceversa.

.
2- document.documentElement.scrollTop: Devuelve el numero de pixeles desplazados al hacer scroll vertical en el elemento documentElement.
.
TENER EN CUENTA QUE SI EL TAMA脩O DE PANTALLA DEL DISPOSITIVO SE REDUCE O SI EL TAMA脩O DE LA VENTANA DEL NAVEGADOR SE REDUCE ENTONCES EL VALOR DE clientHeight SE REDUCIRA Y EL VALOR MAXIMO DE scrollTop AUMENTARA YA QUE AL REDUCIRSE LA VENTANA TOCA HACER MAS SCROLL PARA RECORRER EL ELEMENTO documentElement. SI EL TAMA脩O DE LA VENTANA DEL NAVEGADOR AUMENTA ENTONCES OCURRE LO CONTRARIO
.

3- document.documentElement.scrollHeight: Devuelve la altura total del elemento documentElement en pixeles incluyendo el padding del elemento pero no el border, ni el margin del elemento ni la barra de dezplazamiento horizontal del navegador.
.
Si analizamos nos damos cuenta que la altura total del elemento documentElement es igual a la altura visible de dicho elemento mas el maximo de pixeles desplazados al hacer scroll vertical en dicho elemento, osea, documentElement.scrollHeight es igual a documentElement.clientHeight + documentElement.scrollTop cuando el valor de scrollTop es el maximo

Mi soluci贸n al reto del bot贸n fue agregarle un 鈥genericSection.removeChild(鈥楨lement鈥)鈥 al evento del bot贸n en la funci贸n de TrendingMovies y 鈥Paginaci贸n

Me costo entender como implementar Infine Scroll en la navegaci贸n, pero ah铆 les va mi explicaci贸n:

  1. declaramos la variable page = 1 e inicializamos infiteScroll como undefined.
let page = 1;
let infiniteScroll;
  1. cuando navegemos por la aplicaci贸n, si existe alg煤n valor a infiteScroll ser谩 removido.
function navigator() {
  console.log({ location });

  if (infiniteScroll) {
    window.removeEventListener('scroll', infiniteScroll, { passive: false });
    infiniteScroll = undefined;
  }

  if (location.hash.startsWith('#trends')) {
    trendsPage();
  1. Cuando ingresemos a la pagina de trendsPage, infiniteScroll tendr谩 el valor de getPaginatedTrendingMovies. (dependiendo de hacia donde navegues el valor de infinite Scroll va a cambiar para cargar el api de su pagina)
function trendsPage() {
  infiniteScroll = getPaginatedTrendingMovies;
}
  1. termina de cargar la funci贸n navigation y ejecuta window.addEventListener(鈥榮croll鈥, infiniteScroll,{ passive: false });
function navigator() {
  console.log({ location });

  if (infiniteScroll) {
    window.removeEventListener('scroll', infiniteScroll, { passive: false });
    infiniteScroll = undefined;
  }
  
  if (location.hash.startsWith('#trends')) {
    trendsPage();

  if (infiniteScroll) {
    window.addEventListener('scroll', infiniteScroll, { passive: false });
  }
}

As铆 fue como entend铆 como aplicar infiniteScroll en la navegaci贸n. Espero que le haya servido a alguien esta explicaci贸n.

A mi en lugar de hacer tantos cambios para el infiniteScroll, me funcion贸 simplemente envolverla en una funci贸n flecha:

window.addEventListener('scroll',()=>infiniteScroll());

con eso me ahorr茅 la l贸gica de remover el listener

yo lo hice un poco distinto, espero que no este mal, use otro intersection observer que vea el footer, funciona perfecto, pero a lo mejor juan no lo uso por algun motivo

passive
Un valor booleano que, si es true , indica que la funci贸n especificada por el listener nunca llamar谩 a preventDefault() . Si un oyente pasivo llama a preventDefault() , el agente de usuario no har谩 nada m谩s que generar una advertencia en la consola. Si no se especifica, el valor predeterminado es false , excepto que en navegadores que no sean Safari e Internet Explorer, el valor predeterminado es true para los eventos wheel , rueda del mousewheel , touchstart y touchmove . Consulte Mejorar el rendimiento del desplazamiento con oyentes pasivos para obtener m谩s informaci贸n.

en mi reto mi app no es para moviles y todas las peliculas cargan dentro de un div con tama帽o fijo鈥 estuve pensando como hacer hasta que recorde la herencia, y el div tiene los mismos parametros scrollTop, ScrollHeight (el clientHeight es el tama帽o del div que le pones en css), y funciona igual y es mas exacto, y si quieres usar las misma logica dle profe usa height:auto en tu css

Y si como otra posible solucion habriamos agregado un "div " invisible como lastChild sea cual fuere la seccion que estemos, y un intersection observer que si intersecta al div hacemos el llamado de la funcion?

dentro de la funci贸n trendsPage() en el archivo de Navigation.js constru铆 esto al final:

        let counter = 1

        window.addEventListener('scroll', () => {

        const { 
            scrollTop,
            clientHeight,
            scrollHeight } = document.documentElement;
        
        const scrollIsBottom = (scrollTop + clientHeight) >= scrollHeight - 15;

            if(scrollIsBottom){
                counter++
                getTrendingMovies(page = 1 + counter)
            } //this way we make sure we're loading new content only when the scrollIsBottom results TRUE and at the same time we're at the bottom of the page
        })

As铆 cada vez que se haga scroll crearemos esas variables y la validaci贸n para llamar a getTrendingMovies con el counter (que es un n煤mero que aumentar谩 en 1 cada vez que llamemos esta funci贸n). Adem谩s cada vez que nos remitamos a esa pagina de tendencias no cargar谩 todo completamente sino que volver谩 a cargar solamente las 8 pel铆culas iniciales

El 鈥榝alse鈥 al final de un addEventListener siginifica que el evento ser谩 capturado durante la Bubbling phase.
.
.

驴Qu茅 significa esto de Bubbling phase?

.
.
Cuando le asignamos un evento a un nodo HTML, existen dos fases o etapas a la hora de procesar eventos.
La fase de Capturing y la fase de Bubbling. Es decir, primero el evento viaja desde todo el documento html pasando por todos los nodos hasta el nodo que queremos, luego desde ese nodo el evento se ejecuta con todos los nodos padres.
La captura viaja de 鈥渁fuera鈥 hacia 鈥渁dentro鈥, y luego la burbuja va de 鈥渁dentro鈥 hacia 鈥渁fuera鈥.
.
.

.
.
El evento va de arriba hacia abajo (Capturing down) y luego de abajo hacia arriba (Bubbling up).
El setear el useCapture como TRUE o FALSE, lo que le dice al evento es en cu谩l fase quieres que sea ejecutado.
.
useCapture = true
.
El handler estar谩 seteado en la fase Capturing. El evento llegar谩 hasta el nodo antes que a sus hijos. Se ejecutar谩 primero al tocar ese nodo y luego en la fase de burbuja se ejecutar谩n los eventos de los hijos a los padres.
.
useCapture = false
.
El handler estar谩 seteado en la fase de Bubbling. El evento llegar谩 hasta el nodo despu茅s que sus hijos. Es decir, el evento ir谩 hasta el fondo, rebotar谩 en el 煤ltimo hijo y regresar谩 hasta el nodo que se帽alamos en la fase de bubbling, en el camino de vuelta.
.
Eso quiere decir que si haces esto:

child.addEventListener("click", second);
parent.addEventListener("click", first, true);

.
Cuando le des click a 鈥榗hild鈥 se ejecutar谩 el m茅todo 鈥榝irst鈥 antes que 鈥榮econd鈥, porque est谩 useCapture como false (que es su forma por defecto). Es decir, primero el evento se detendr谩 en el 鈥減arent鈥 y luego ir谩 hasta el 鈥渃hild鈥, rebota el evento y ejecutar谩 鈥榮econd鈥.

Para mi fortuna ya habia usado el clientHeight y el scrollHeight para mis carruseles de mi pagina de incio (hice un indicador de progreso de scroll), asi que al nombrarlo entendi de lo que hablaban鈥 sin embargo me parece que se complico un poco todo XD pero de nuevo, para mi fortuna yo estoy haciendo mi pagina diferente, solo tengo en cuenta lo que hace el profe pero a estas alturas del proyecto no puedo aplicar muchas de las cosas tal cual el las propone, lo que en cierta forma significa un reto para mi cada nuevo 鈥渇eature鈥 y eso me agrada.

Mucha suerte compa帽eros y animo鈥 les dejo un screenshoot de mi pagina de incio :3

Para el infinity scroll yo use otro intersection observer en la 煤ltima pel铆cula cargada, y de esta forma volvia a ejecutar la funci贸n getTrendingMovies() aunmentando page y luego hacia la validaci鈥檕n:

if(lastMovieInterception){
    observadorMoreMovies.unobserve(lastMovieInterception)
  }

Yo solucion茅 todo el problema del evento scroll usando

    document.onscroll = () => getPaginatedMovies('trending/movie/day')

Por cada p谩gina, se llama a getPaginatedMovies con un endpoint diferente. Despu茅s se podr铆an hacer cosas como poner todos los endpoints en variables, llevar a document.onscroll a navigator, etc. pero no me compliqu茅 mucho.

Aqu铆 la funci贸n para detectar si el usuario alcanz贸 el l铆mite de scrolling inferior:

const scrollBottomReached = () => {
    const {scrollTop, scrollHeight, clientHeight } = document.documentElement;
    return (scrollTop + clientHeight) >= (scrollHeight - 15);
}

Que se puede usar elegantemente:

window.addEventListener('scroll', () => {
	if(scrollBottomReached()){
		// Aqu铆 tu l贸gica
	}
})

Hola, muchas gracias por los aportes anteriores. Excelente clase, he tenido que verla algunas veces. Comparto mi c贸digo, con el fin de saber si tiene alguna contra hacerlo de este modo, los resultados en la app son los mismos.

function getTrendingMovies() {    
    createMovies(ENDPOINT_TRENDING, genericSection, {}, { lazyLoad: true, clean: true,});    
};

window.addEventListener('scroll', () => {
    const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
    const scrollIsBottom = ( scrollTop + clientHeight) >= (scrollHeight - 1);
    if (scrollIsBottom) {
        createMovies(ENDPOINT_TRENDING, genericSection, {
            params: {
                page: page++,
            },
        }, {
                lazyLoad: true,
                clean: false,
            },
        );
    };
}); 

Amigos por favor tener en cuenta que en esta parte del codigo:

const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
  const scrollIsBottom = (scrollTop + clientHeight) >= (scrollHeight - 15);

se suma el scrollTop y el clientHeight, yo los tenia restando y dure un buen rato tratando de ver cual era el error, era un signo. Atencion a los pequenios detalles

Yo lo hice con React

import InfiniteSroll from './InfiniteSroll'

function MyComponent() {
	 const onInfiniteScroll = () => console.log('onInfiniteScroll')
	return <InfiniteScroll onInfiniteScroll={onInfiniteScroll}>
		// ... algo como una lista
	</InfiniteScroll>
}
// InfiniteScroll.js
import PropTypes from 'prop-types'
import { useEffect } from 'react'

const InfiniteScroll = ({ children, onInfiniteScroll }) => {
  useEffect(function setupListener() {
    function infiniteScroll() {
      const { scrollTop, scrollHeight, clientHeight } = document.documentElement
      const scrollIsBottom = scrollTop + clientHeight >= scrollHeight - 10
      if (scrollIsBottom) {
        onInfiniteScroll()
      }
    }
    window.addEventListener('scroll', infiniteScroll)

    return function cleanupListener() {
      window.removeEventListener('scroll', infiniteScroll)
    }
  })

  return (
    <div id="wrapper">
      <div id="content">{children}</div>
      <div id="last" />
    </div>
  )
}

InfiniteScroll.propTypes = {
  children: PropTypes.node.isRequired,
  onInfiniteScroll: PropTypes.func.isRequired,
}

export default InfiniteScroll

Mi propuesta propuesta es reutilizar las funciones de petiiciones de datos agregando un par谩metro por defecto de p谩gina 1 cuando se ejecuta la primera vez, y luego con el evento scroll all铆 s铆 colocamos la p谩gina que es el page de la variable global. para esto necesitaremos una funci贸n para determinar si el scroll est谩 en el umbral

const scrollIsOnThreshold = () => {
    const { scrollTop, clientHeight, scrollHeight } = document.documentElement;
    const scrollDiff = scrollHeight - (scrollTop + clientHeight);
    const scrollIsBottom = scrollDiff <= 30;
    if (scrollIsBottom) page += 1;
    return scrollIsBottom;
};

Si est谩 en el umbral para hacer el trigger entonces aumentamos de p谩gina y retornamos el resultado (true), luego creamos el callback infiniteScroll bas谩ndonos en esta funci贸n y la funci贸n promesa reutilizada.

const trendsPage = () => {
    	.
	.
	.
    // Obteniendo los datos a renderizar
    getData.getTrendingMovies();
    // Scroll infinito
    infiniteScroll = () => {
        if (scrollIsOnThreshold()) getTrendingMovies(page);
    };
};

.
.
Mi propuesta en el reposiitorio, commit actual : Click aqu铆i

Mencionar que para la soluci贸n que propone el profesor se tiene que crear una funci贸n de m谩s pel铆culas para cada vista, sea de b煤squeda, de tendencias o de categor铆as, porque tienen distintos par谩metros.

As铆 qued贸 mi proyecto.

https://rica999.github.io/BROWSER-MOVIES-MOVIEDB/

Repositorio: https://github.com/rica999/BROWSER-MOVIES-MOVIEDB

Se me hizo infinite scroll absolutamente toda mi app y ni siquiera se porque 馃槀 solo aplique la l贸gica de los scrollTop, scrollHeigth, y clientHeigth con el if de validaci贸n y nada mas y ahora en cualquier p谩gina tengo infinite scroll, ni siquiera use la parte donde el profe declara la variable infiniteScroll ni el eventListener, sin embargo entro en los botones de c/categoria y tengo scroll infinito.
Lo gracioso es que es de las primeras veces que me sale algo y nisiquiera se el porque 馃槀馃槺, claramente mi app esta dise帽ada diferente a la del profe desde el inicio en cuesti贸n de maquetaci贸n y eso

Usar un Intersection Observer haria la misma funcion que escuchar el evento scroll en todo el body, no? El nodo a observar ya quedaria en la imaginacion de cada quien鈥 ( a mi se me ocurriria observar el footer o la ultima pelicula鈥)
Segun un estudio en este articulo, llamar una funcion por cada scroll puede darle demasiada carga al hilo principal. En esta app pequena a lo mejor no hace tanto efecto, pero hay que tomarlo en cuenta. 馃槂

A mi me funciono todo bien sin usar el false del tercer par谩metro del addEventListener.