Carga diferida de imágenes en Svelte

Índice
  1. Trabajamos con un ejemplo de la vida real.
  2. Iniciamos rápidamente Svelte
  3. Agregar la carpeta de componentes
  4. Observando la intersección
  5. Cargando las imágenes
  6. Valores de propiedad de ranura
  7. Mostrando imágenes al cargar
  8. Carga diferida nativa
  9. ¡Conectémoslo todo!

Una forma sencilla de mejorar la velocidad de un sitio web es descargar imágenes únicamente cuando sean necesarias, que sería cuando ingresen a la ventana gráfica. Esta técnica de “carga diferida” existe desde hace algún tiempo y hay muchos tutoriales excelentes sobre cómo implementarla.

Pero incluso con todos los recursos disponibles, la implementación de la carga diferida puede verse diferente según el proyecto en el que esté trabajando o el marco que esté utilizando. En este artículo, usaré la API de Intersection Observer junto con el onLoadevento para cargar imágenes de forma diferida con el marco Svelte JavaScript.

Consulte la introducción de Tristram Tolliday a Svelte si es nuevo en el marco.

Trabajamos con un ejemplo de la vida real.

Preparé este enfoque mientras probaba la velocidad en una aplicación Svelte and Sapper en la que trabajo, Shop Ireland. Uno de nuestros objetivos es hacerlo lo más rápido posible. Llegamos a un punto en el que la página de inicio estaba sufriendo un impacto en el rendimiento porque el navegador estaba descargando un montón de imágenes que ni siquiera estaban en la pantalla, por lo que, naturalmente, optamos por cargarlas de forma diferida.

Svelte ya es bastante rápido porque todo el código se compila de antemano. Pero una vez que incorporamos la carga diferida para las imágenes, las cosas realmente empezaron a acelerarse.

Esto es en lo que vamos a trabajar juntos. No dudes en obtener el código final de esta demostración de GitHub y seguir leyendo para obtener una explicación de cómo funciona.

Aquí es donde terminaremos al final:

Iniciamos rápidamente Svelte

Es posible que ya tengas una aplicación Svelte que te gustaría usar, pero si no, comencemos un nuevo proyecto Svelte y trabajamos en él localmente. Desde la línea de comando:

npx degit sveltejs/template my-svelte-projectcd my-svelte-projectnpm installnpm run dev

Ahora deberías tener una aplicación para principiantes ejecutándose en http://localhost:5000.

Agregar la carpeta de componentes

La demostración inicial de Svelte tiene un App.sveltearchivo pero aún no tiene componentes. Configuramos los componentes que necesitamos para esta demostración. No hay una carpeta de componentes, así que creemos una en la srccarpeta. Dentro de esa carpeta, cree una Imagecarpeta; Aquí contendrá nuestros componentes para esta demostración.

Vamos a hacer que nuestros componentes hagan dos cosas. Primero, verificará cuándo ingresa una imagen a la ventana gráfica. Luego, cuando ingresa una imagen, los componentes esperarán hasta que el archivo de imagen se haya cargado antes de mostrarlo.

El primer componente será un IntersectionObserverque envuelve al segundo componente, un ImageLoader. Lo que me gusta de esta configuración es que permite que cada componente se centre en hacer una cosa en lugar de intentar agrupar un montón de operaciones en un solo componente.

Comenzamos con el IntersectionObservercomponente.

Observando la intersección

Nuestro primer componente será una implementación funcional de la API de Intersection Observer. El Intersection Observer es algo bastante complejo, pero lo esencial es que observa un elemento secundario y nos informa cuando ingresa al cuadro delimitador de su padre. Por lo tanto, las imágenes: pueden ser hijas de algún elemento principal y podemos recibir un aviso cuando se desplazan a la vista.

Si bien definitivamente es una gran idea para familiarizarse con los entresijos de la API de Intersection Observer (y Travis Almand tiene un excelente artículo sobre ella), vamos a utilizar un útil componente Svelte que Rich Harris preparó para esvelte.dev.

Primero configuraremos esto antes de profundizar en qué hace exactamente. Cree un nuevo IntersectionObserver.sveltearchivo y suéltelo en la src/components/Imagecarpeta. Aquí es donde definiremos el componente con el siguiente código:

script  import { onMount } from 'svelte';
  export let once = false;  export let top = 0;  export let bottom = 0;  export let left = 0;  export let right = 0;
  let intersecting = false;  let container;
  onMount(() = {    if (typeof IntersectionObserver !== 'undefined') {      const rootMargin = `${bottom}px ${left}px ${top}px ${right}px`;
      const observer = new IntersectionObserver(entries = {        intersecting = entries[0].isIntersecting;        if (intersecting  once) {          observer.unobserve(container);        }      }, {        rootMargin      });
      observer.observe(container);      return () = observer.unobserve(container);    }
    // The following is a fallback for older browsers    function handler() {      const bcr = container.getBoundingClientRect();
      intersecting = (        (bcr.bottom + bottom)  0         (bcr.right + right)  0         (bcr.top - top)  window.innerHeight         (bcr.left - left)  window.innerWidth      );
      if (intersecting  once) {        window.removeEventListener('scroll', handler);      }    }
    window.addEventListener('scroll', handler);    return () = window.removeEventListener('scroll', handler);  });/script
style  div {    width: 100%;    height: 100%;  }/style
div bind_this={container}  slot {intersecting}/slot/div

Podemos usar este componente como envoltorio alrededor de otros componentes, y determinará por nosotros si el componente envuelto se cruza con la ventana gráfica.

Si está familiarizado con la estructura de los componentes de Svelte, verá que sigue un patrón que comienza con scripts, pasa a estilos y luego termina con marcado. Establece algunas opciones que podemos pasar, incluida una oncepropiedad, junto con valores numéricos para las distancias superior, derecha, inferior e izquierda desde el borde de la pantalla que define el punto donde comienza la intersección.

Ignoraremos las distancias y en su lugar haremos uso de la oncepropiedad. Esto asegurará que las imágenes solo se cargan una vez, cuando ingresan a la ventana gráfica.

La lógica principal del componente está dentro de la onMountsección. Esto configura nuestro observador, que se utiliza para nuestro elemento de verificación y determina si se “interseca” con el área visible de la pantalla.

Para navegadores más antiguos, también adjunte un evento de desplazamiento para verificar si el elemento es visible a medida que nos desplazamos, y luego eliminará este oyente si hemos determinado que es viable y eso oncees true.

Cargando las imágenes

Usemos nuestro IntersectionObservercomponente para cargar imágenes condicionalmente envolviéndolo alrededor de un ImageLoadercomponente. Nuevamente, este es el componente que recibe una notificación IntersectionOberserverpara saber que es hora de cargar una imagen.

Eso significa que necesitaremos un nuevo archivo de componente en formato components/Image. Llamémoslo ImageLoader.svelte. Aquí está el código que queremos en él:

script  export let src  export let alt
  import IntersectionObserver from './IntersectionObserver.svelte'  import Image from './Image.svelte'  /script
IntersectionObserver once={true} let_intersecting={intersecting}  {#if intersecting}    Image {alt} {src} /  {/if}/IntersectionObserver

Este componente requiere algunos accesorios relacionados con la imagen ( srcy alt) que usaremos para crear el marcado real de una imagen. Observe que estamos importando dos componentes en la sección de scripts, incluido el que IntersectionObserveracabamos de crear y otro llamado Imageque aún no hemos creado, pero al que llegaremos en un momento.

Se IntersectionObserverpone a trabajar actuando como un voltorio alrededor del componente que pronto se creará Image. Mira esas propiedades en él. Estamos configurando oncepara trueque la imagen solo se cargue la primera vez que la veamos.

Luego hacemos uso de los accesorios de tragamonedas de Svelte. ¿Que son esos? Cubramos eso a continuación.

Valores de propiedad de ranura

Los componentes de envoltura, como el nuestro, IntersectionObserverson útiles para pasar accesorios a los niños que contiene. Svelte nos ofrece algo llamado accesorios de tragamonedas para que eso suceda.

En nuestro IntersectionObservercomponente es posible que hayas anotado esta línea:

slot {intersecting}/slot

Esto es pasar el accesorio de intersección a cualquier componente que le demos. En este caso, nuestro componente ImageLoader recibe el accesorio cuando usa el contenedor. Accedemos al accesorio usando let_intersecting={intersecting} así:

IntersectionObserver once={true} let_intersecting={intersecting}

Luego podemos usar el valor de intersección para determinar cuándo es el momento de cargar un Imagecomponente. En este caso, usamos una condición si para verificar cuándo es el momento de comenzar:

IntersectionObserver once={true} let_intersecting={intersecting}  {#if intersecting}    Image {alt} {src} /  {/if}/IntersectionObserver 

Si se produce la intersección, Imagese carga y recibe los accesorios alty src. Puedes aprender un poco más sobre los accesorios de las tragamonedas en este tutorial de Svelte.

Ahora tenemos el código implementado para mostrar un Imagecomponente cuando se desplaza por la pantalla. Finalmente comenzamos a construir el componente.

Mostrando imágenes al cargar

Sí, lo has adivinado: agregamos un Image.sveltearchivo a la components/Imagecarpeta de nuestro Imagecomponente. Este es el componente que recibe nuestros altaccesorios srcy los coloca en un imgelemento.

Aquí está el código del componente:

script  export let src  export let alt
  import { onMount } from 'svelte'
  let loaded = false  let thisImage
  onMount(() = {    thisImage.onload = () = {      loaded = true    }  }) 
/script
style  img {    height: 200px;    opacity: 0;    transition: opacity 1200ms ease-out;  }  img.loaded {    opacity: 1;  }/style
img {src} {alt} class:loaded bind_this={thisImage} /

De buenas a primeras, estamos recibiendo los altaccesorios y srcantes de definir dos nuevas variables: loadedpara almacenar si la imagen se ha cargado o no, y thisImagepara almacenar una referencia al propio elemento DOM img.

También estamos usando un método útil llamado Svelte onMount. Esto nos brinda una forma de llamar funciones una vez que un componente se ha representado en el DOM. En este caso, configuramos una devolución de llamada para thisImage.onload. En términos sencillos, eso significa que se ejecuta cuando la imagen ha terminado de cargarse y establecerá la loadedvariable en un truevalor.

Usaremos CSS para revelar la imagen y desvanecerla a la vista. Activemos opacity: 0las imágenes para que inicialmente sean invisibles, aunque técnicamente están en la página. Luego, cuando se cruzan con la ventana gráfica y ImageLoaderotorgan permiso para cargar la imagen, configuraremos la imagen en opacidad total. Podemos hacer que sea una transición suave estableciendo la transitionpropiedad en la imagen. La demostración establece el tiempo de transición en 1200 ms, pero puede acelerarlo o ralentizarlo según sea necesario.

Eso nos lleva a la última línea del archivo, que es el marcado de un imgelemento.

img {src} {alt} class:loaded bind_this={thisImage} /

Esto se utiliza class:loadedpara aplicar condicionalmente una .loadedclase si la variable cargada es true. También utiliza el bind:thismétodo para asociar este elemento DOM con la thisImagevariable.

Carga diferida nativa

Si bien la compatibilidad con la carga diferida nativa en los navegadores casi está aquí, aún no es compatible con todas las versiones estables actuales. Aún podemos agregarle soporte mediante una simple verificación de capacidad.

En nuestro ImageLoader.sveltearchivo podemos incorporar la onMountfunción y, dentro de ella, verificar si nuestro navegador admite la carga diferida.

import { onMount } from 'svelte'let nativeLoading = false// Determine whether to bypass our intersecting checkonMount(() = {  if ('loading' in HTMLImageElement.prototype) {    nativeLoading = true  }})

Luego ajustamos nuestra ifcondición para incluir este nativeLoadingbooleano.

{#if intersecting || nativeLoading}  Image {alt} {src} /{/if}

Por último, en Image.svelte, le decimos a nuestro navegador que utilice la carga diferida agregando elementos loading="lazy"al imgelemento.

img {src} {alt} class:loaded bind_this={thisImage} /

Esto permitirá que los navegadores modernos y futuros omitan nuestro código y se encarguen de la carga diferida de forma nativa.

¡Conectémoslo todo!

Muy bien, es hora de utilizar nuestro componente. Abra el App.sveltearchivo y coloque el siguiente código para importar nuestro componente y usarlo:

script  import ImageLoader from './components/Image/ImageLoader.svelte';/script
ImageLoader src="OUR_IMAGE_URL" alt="Our image"/ImageLoader

Aquí está la demostración una vez más:

Y recuerde que puede descargar el código completo de esta demostración en GitHub. Si desea ver esto funcionando en un sitio de producción, consulte mi proyecto Shop Ireland. La carga diferida se utiliza en la página de inicio, las páginas de categorías y las páginas de búsqueda para ayudar a acelerar las cosas. ¡Espero que te resulte útil para tus propios proyectos Svelte!

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion