Algunos usos funcionales para que el observador de intersecciones sepa cuándo un elemento está a la vista | Programar Plus

Puede que no lo sepas, pero JavaScript ha acumulado sigilosamente una gran cantidad de observadores en los últimos tiempos, e Intersection Observer es parte de ese arsenal. Observadores son objetos que detectan algo en tiempo real, como los observadores de aves que van a su lugar favorito para sentarse y esperar a que lleguen.

Diferentes observadores observan cosas diferentes (no todos observan a los halcones).

El primer observador que conocí fue el Mutation Observer que busca cambios en el árbol DOM. Fue único en su tipo en ese momento, pero ahora tenemos muchos más observadores.

Intersection Observer observa la “intersección” (es decir, el paso a través) de un elemento a través de uno de sus elementos ancestros o el área en la pantalla donde la página es visible (también conocida como la ventana gráfica).

Es como ver un tren pasar por una estación. Puede ver cuándo llega el tren, cuándo sale y cuánto tiempo estuvo parado.

Saber cuándo un elemento está a punto de aparecer, si ha desaparecido o cuánto tiempo ha pasado desde que apareció, todas tienen aplicaciones útiles. Entonces, veremos algunos de esos casos de uso ahora, justo después de ver el código para crear un IntersectionObserver objeto a través de la API Intersection Observer.

Una descripción general rápida de IntersectionObserver

La API de Intersection Observer ya ha ganado un amplio soporte en el momento de escribir este artículo.

Estos datos de soporte del navegador son de Caniuse, que tiene más detalles. Un número indica que el navegador admite la función en esa versión en adelante.

Escritorio

Cromo Firefox ES DECIR Borde Safari
58 55 No dieciséis 12,1

Móvil / Tableta

Android Chrome Android Firefox Androide Safari de iOS
96 94 96 12,2-12,5

Pero si desea verificar si Intersection Observer es compatible mientras trabaja con él, puede ver si la propiedad IntersectionObserver existe en el window objeto:

if(!!window.IntersectionObserver){}
/* or */
if('IntersectionObserver' in window){}

Bien, ahora para ver la creación del objeto:

var observer = new IntersectionObserver(callback, options);

El IntersectionObserver El constructor del objeto toma dos parámetros. El primero es un llamar de vuelta función que se ejecuta una vez que el observador nota una intersección y ha entregado de forma asincrónica algunos datos sobre esa intersección.

El segundo parámetro (opcional) es opciones, un objeto con información para definir lo que será la “intersección”. Es posible que no queramos saber cuándo un elemento está a punto de aparecer, pero solo cuando esté completamente visible. Algo así se define a través del parámetro de opciones.

Las opciones tienen tres propiedades:

  • root – El elemento ancestro / ventana gráfica que intersecará el elemento observado. Piense en ello como la estación de tren en la que se cruzará el tren.
  • rootMargin – Un perímetro del elemento raíz, reduciendo o aumentando el área del elemento raíz para vigilar la intersección. Es similar al CSS margin propiedad.
  • threshold – Una matriz de valores (entre 0 y 1.0), cada uno de los cuales representa la distancia a la que un elemento se ha cruzado o cruzado en la raíz en la que se activará la devolución de llamada.

Digamos que nuestro umbral es 0,5. La devolución de llamada se activa cuando el elemento está dentro o supera su umbral medio visible. Si el valor es [0.3, 0.6], la devolución de llamada se activa cuando el elemento está dentro o supera su umbral visible del 30% y también, su umbral visible del 60%.

Eso es suficiente teoría ahora. Veamos algunas demostraciones. Primero, carga diferida.

Caso de uso 1: carga diferida de imágenes

Ver la pluma
Observador de intersecciones – Carga diferida por Preethi Sam (@rpsthecoder)
en CodePen.

Para ver la carga en la marca, vea esta página web ya que la demostración incrustada no muestra eso.

Programar Plusha cubierto completamente la carga diferida antes y, por lo general, se hace así: muestra un marcador de posición liviano donde se pretenden las imágenes, luego cámbialas por las imágenes deseadas a medida que aparecen (o están a punto de aparecer) a la vista. Créame, no hay nada de flojo en implementar esto, es decir, hasta que tengamos algo nativo con lo que trabajar.

Aplicaremos la misma mecánica. Primero, tenemos un montón de imágenes y hemos definido una imagen de marcador de posición para mostrar inicialmente. Estamos utilizando un atributo de datos que lleva la URL de la imagen original que se mostrará y que define la imagen real que se cargará cuando aparezca.

<img src="https://css-tricks.com/a-few-functional-uses-for-intersection-observer-to-know-when-an-element-is-in-view/placeholder.png" data-src="img-1.jpg">
<img src="https://css-tricks.com/a-few-functional-uses-for-intersection-observer-to-know-when-an-element-is-in-view/placeholder.png" data-src="img-2.jpg">
<img src="https://css-tricks.com/a-few-functional-uses-for-intersection-observer-to-know-when-an-element-is-in-view/placeholder.png" data-src="img-3.jpg">
<!-- more images -->

El resto son secuencias de comandos.

let observer = new IntersectionObserver(
(entries, observer) => { 
  entries.forEach(entry => {
    /* Here's where we deal with every intersection */
  });
}, 
{rootMargin: "0px 0px -200px 0px"});

La función de devolución de llamada anterior es una función de flecha (aunque puede usar una función normal en su lugar).

La función de devolución de llamada recibe dos parámetros: un conjunto de entradas llevando la información sobre cada intersección y el observador sí mismo. Esas entradas se pueden filtrar o recorrer en bucle para que podamos ocuparnos de las entradas de intersección que queramos. En cuanto a las opciones, solo he proporcionado las rootMargin valor, dejando que el root y threshold las propiedades caen en sus valores predeterminados.

El root por defecto es la ventana gráfica y threshold el valor predeterminado es 0, que se puede traducir aproximadamente como “¡envíame un ping en el mismo momento en que el elemento aparece en la ventana gráfica!”

La rareza, sin embargo, es que reduje el área de observación de la ventana gráfica en doscientos píxeles en la parte inferior usando rootMargin. Normalmente no haríamos esto para la carga diferida. En su lugar, podríamos aumentar el margen o dejarlo predeterminado. Pero reducir no es algo que normalmente haríamos en esta situación. Lo hice solo porque quiero demostrar que las imágenes originales se cargan en el umbral en el área observada. De lo contrario, toda la acción pasaría fuera de la vista.

Cuando la imagen se cruza con el área del observador de la ventana gráfica (que está 200px por encima de la parte inferior en la demostración), reemplazamos la imagen del marcador de posición con la imagen real.

let observer = new IntersectionObserver(
(entries, observer) => { 
entries.forEach(entry => {
    /* Placeholder replacement */
    entry.target.src = entry.target.dataset.src;
    observer.unobserve(entry.target);
  });
}, 
{rootMargin: "0px 0px -200px 0px"});

entry.target es el elemento observado por el observador. En nuestro caso, esos son los elementos de la imagen. Una vez que el marcador de posición se reemplaza en un elemento de imagen, ya no tenemos que observarlo, por lo que llamamos al observador unobserve método para ello.

Ahora que el observador está listo, es hora de comenzar a observar todas las imágenes utilizando su observer método:

document.querySelectorAll('img').forEach(img => { observer.observe(img) });

¡Eso es! hemos cargado las imágenes de forma diferida. En la próxima demostración.

Caso de uso 2: pausar automáticamente el video cuando está fuera de la vista

Digamos que estamos viendo un video en YouTube y (por el motivo que sea) queremos desplazarnos hacia abajo para leer los comentarios. No sé ustedes, pero normalmente no pause el video antes de hacer eso, lo que significa que me pierdo parte del video mientras navego.

¿No sería bueno que el video se detuviera cuando nos desplazamos fuera de él? Sería aún mejor si el video se reanudara cuando vuelva a estar a la vista, por lo que no es necesario presionar Reproducir o Pausar en absoluto.

Intersection Observer ciertamente puede hacer eso.

Ver la pluma
IntersectionObserver: pausa automática fuera de la vista de video de Preethi Sam (@rpsthecoder)
en CodePen.

Aquí está nuestro video en HTML:

<video src="https://css-tricks.com/a-few-functional-uses-for-intersection-observer-to-know-when-an-element-is-in-view/OSRO-animation.mp4" controls=""></video>

Así es como cambiamos entre reproducción y pausa:

let video = document.querySelector('video');
let isPaused = false; /* Flag for auto-paused video */
let observer = new IntersectionObserver((entries, observer) => { 
  entries.forEach(entry => {
    if(entry.intersectionRatio!=1  && !video.paused){
      video.pause(); isPaused = true;
    }
    else if(isPaused) {video.play(); isPaused=false}
  });
}, {threshold: 1});
observer.observe(video);

Antes de mostrarles cómo estamos pausando y reproduciendo el video durante cada intersección (es decir, entrada), quiero llamar su atención sobre el threshold propiedad de las opciones.

Th threshold tiene un valor de 1. Ambos root y rootMargin será predeterminado. Esto es lo mismo que decir “oye, avísame tan pronto como el elemento esté completamente visible en la ventana gráfica”.

Una vez que ocurre la intersección y se activa la devolución de llamada, hacemos una pausa o reproducimos el video según esta lógica:

Un diagrama de flujo para alternar la reproducción y la pausa en un video, donde si el video no es completamente visible y no está en pausa, entonces isPaused es verdadero.  Pero si el video se pausó automáticamente, entonces IsPaused es falso.

No he llamado unobserve para el video, por lo que el observador sigue observando el video y hace una pausa cada vez que se pierde de vista.

Caso de uso 3: ver cuánto contenido se ve

Esto se puede interpretar e implementar de muchas maneras dependiendo de cuál sea su contenido y la forma en que prefiera medir cuánto se ha visto.

Para un ejemplo simple, observaremos el último párrafo de cada artículo en una lista de artículos en una página. Una vez que el último párrafo de un artículo se vuelve completamente visible, lo consideraremos leído, como si dijéramos que ver el último vagón de un tren cuenta como haber visto el tren completo.

Aquí hay una demostración que muestra dos artículos en una página, cada uno con varios párrafos.

Ver la pluma
IntersectionObsever: contenido visto por Preethi Sam (@rpsthecoder)
en CodePen.

Nuestro HTML simplificado es algo como esto:

<div id="count"><!-- The place where "number of articles viewed" is displayed --></div>

<h2>Article 1</h2>
<article>
  <p><!-- Content --></p>
  <!-- More paragraphs -->
</article>
<h2>Article 2</h2>
<article>
  <p><!-- Content --></p>
  <!-- More paragraphs -->
</article>
<!-- And so on... -->
let n=0; /* Total number of articles viewed */
let count = document.querySelector('#count');
let observer = new IntersectionObserver((entries, observer) => { 
  entries.forEach(entry => {
    if(entry.isIntersecting){
      count.textContent= `articles fully viewed - ${++n}`; 
      observer.unobserve(entry.target);
    }
  });
}, {threshold: 1});

document.querySelectorAll('article > p:last-child').forEach(p => { observer.observe(p) });

Durante cada intersección, la vista completa del último párrafo de un artículo, estamos incrementando un recuento: n, que representa el número total de artículos leídos. Luego mostramos ese número encima de la lista de artículos.

Una vez que hemos contado en una intersección del último párrafo, ya no es necesario observarlo, por lo que llamamos unobserve para ello.

¡Gracias por acompañarnos!

Eso es todo por los ejemplos que veremos juntos para esta publicación. Probablemente tenga una idea de cómo se usa, para poder observar elementos y desencadenar eventos en función de dónde se cruzan con la ventana gráfica.

Dicho esto, vale la pena tener cuidado al realizar cambios visuales basados ​​en los datos de intersección obtenidos a través del observador. Claro, Intersection Observer no tiene problemas cuando se trata de registrar datos de intersecciones. Pero cuando se usa para realizar cambios en pantalla, debemos asegurarnos de que los cambios no se retrasen, lo cual es una posibilidad porque básicamente estamos haciendo cambios basados ​​en los datos recuperados de forma asincrónica. Eso podría requerir un poco de tiempo para cargarse.

Como vimos, cada entrada de intersección tiene un conjunto de propiedades que transmiten información sobre la intersección. No los cubrí todos en esta publicación, así que asegúrese de revisarlos.

(Visited 3 times, 1 visits today)