Scroll infinito con JavaScript nativo usando fetch

Hacía mucho tiempo que quería hablar sobre como se puede implementar la funcionalidad de scroll infinito en una lista de elementos que pudiera haber en cualquier página Web.

El scroll infinito es una técnica que permite al usuario interactuar con el ratón o mouse desplazándose con el scroll hacía abajo para cargar nuevo contenido dinámico.

De esta manera, el scroll se hace infinito y el tiempo de carga inicial mejora considerablemente.

No yendo muy lejos, por ejemplo, una plataforma Ecommerce tiene que mostrar productos por categorías si o si. Normalmente, suelen funcionar con paginación ya sea con PHP o JavaScript.Te

¿Te has planteado que tal sería la paginación de productos con scroll infinito?

El scroll infinito también lo utilizan plataformas como Facebook, Twitter o Tik Tok para ir mostrando noticias o publicaciones a medida que se va avanzando con el scroll del ratón.

Las redes sociales son un escenario ideal, al menos nos han acostumbrado a eso pero,  es que quizá si hubiera una paginación en estos sitios webs con tanto contenido que requiere clic del usuario para mostrar más información, es más probable que se acaben cansando y no naveguen tanto.

Las páginas webs de una sola página cada vez son más tendencia y no es casualidad.

¿No tienes la sensación de que el scroll infinito mejora la navegación?

El scroll infinito puede ser un excelente recurso para mostrar tu contenido pero debes emplearlo de forma correcta.

Antes de decidir a la ligera que deseas emplear el scroll infinito, debes tener muy en cuenta sus ventajas e inconvenientes.

Ventajas del scroll infinito

  • Hace que los usuarios estén pendientes y esto hace que aumente el tiempo de navegación.
  • Aumenta el tiempo de sesión.
  • Se ha estudiado que los usuarios llegan a elementos que con paginación jamás llegarían.
  • Perfecto para pantallas táctiles.
  • Ideal para dispositivos móviles.
  • Ideal para el contenido visual.
  • Es más atractivo y moderno.

Inconvenientes del scroll infinito

  • Problemas con el pie de página que prácticamente no se muestra hasta el final del contenido.
  • Organización del contenido inexistente.
  • Encontrar un elemento en concreto es difícil. Por ejemplo, en paginación clásica si que es posible acceder a una página para acceder a un elemento.
  • Problemas de tiempos con carga de imágenes grandes en cada iteración.

En este artículo vas a aprender como implementar un sistema de scroll infinito en tu página web utilizando simplemente JavaScript y llamadas asíncronas al servidor.

Código HTML

En la plantilla o archivo HTML tan solo voy a agregar una lista de elementos vacía:

<ul class="items row"></ul>

Para la parte visual, me apoyaré con el diseño de Bootstrap 4.

Por eso estoy declarando una lista desordenada <ul> con la clase .row para definir una fila.

La clases «items» la usaré para acceder a la lista mediante JavaScript.

Código JavaScript

Atento a este apartado porque la clave del asunto está en entender el código JavaScript que en definitiva es el conducto que consulta los datos del servidor para mostrarlos en la pantalla.

var start = 0;
var limit = 12;
var endItems = false;
 
window.addEventListener('scroll', () => {
    if (window.scrollY == document.documentElement.scrollHeight - window.innerHeight) {
        getItems();
    }
});
 
window.onload = function() {
    getItems();
}
 
function getItems() {
    if (endItems) {
        return;
    }  
 
    let params = new FormData();
    params.append('start', start);
    params.append('limit', limit);
 
    fetch('ajax.php', {
        method: 'post',
        body: params,
    }).then(function(response) {
        if (response.ok) {
            return response.json();
        } else {
            throw 'Error en llamada al servidor';
        }
    }).then(function(items) {
        if (items.endItems) {
            endItems = true;
        } else {
            var html = '';
            items.forEach(function(element) {
                html += `
                    <li class="col-lg-3">
                        <div class="card mb-3">
                            <div class="card-body">
                                <h5 class="card-title">${element.name}</h5>
                                <p class="card-text">${element.description}</p>
                                <p class="card-text">Cantidad: ${element.quantity}</p>
                                <p class="card-text">Precio: ${element.price}</p>
                                <p class="card-text">Total: ${element.price * element.quantity}</p>
                                <a href="#" class="btn btn-primary">Comprar ahora</a>
                            </div>
                        </div>
                    </li>
                `;
            });
 
            const current_items = document.querySelector(".items");
            current_items.innerHTML += html;
            start += limit;
        }
    }).catch(function(error) {
        console.log(error);
    });
}

En este código estoy definiendo 3 variables globales:

  • start: para definir el inicio del límite de la consulta SQL en la base de datos. Inicialmente, la iniciamos en 0 para conseguir los primeros registros. Esta variable irá cambiando su valor a medida que hacemos scroll con el ratón.
  • limit: se usa para definir el número de elementos por página. En este caso nos interesa que sea 12 para mostrar 3 filas en 4 columnas.
  • endItems: es una variable booleana que uso para identificar cuando estamos en el final de la lista de elementos. Inicialmente, empieza en false.

A continuación, capturamos el evento de scroll para comprobar cuando hemos llegado a la parte de abajo con el siguiente trozo de código:

window.addEventListener('scroll', () => {
    if (window.scrollY == document.documentElement.scrollHeight - window.innerHeight) {
        getItems();
    }
});

La función getItems() es la que se encargará de ir a buscar al servidor la información para retornar de vuelta los elementos que tocan.

Lógicamente, como hemos definido nuestra lista vacía en el HTML, al cargar la página llamaremos también a nuestra función getItems():

window.onload = function() {
    getItems();
}

En la función getItems() lo primero que hacemos es comprobar si hemos llegado al final de la lista. Si es así, páramos la ejecución.

if (endItems) {
    return;
}

En caso contrario, preparamos los parámetros que deseamos enviar al servidor con:

let params = new FormData();
params.append('start', start);
params.append('limit', limit);

Para hacer la llamada al servidor uso fetch de la siguiente manera:

fetch('ajax.php', {
    method: 'post',
    body: params,
}).then(function(response) {
    if (response.ok) {
        return response.json();
    } else {
        throw 'Error en llamada al servidor';
    }
}).then(function(items) {
    if (items.endItems) {
        endItems = true;
    } else {
        var html = '';
        items.forEach(function(element) {
            html += `
                <li class="col-lg-3">
                    <div class="card mb-3">
                        <div class="card-body">
                            <h5 class="card-title">${element.name}</h5>
                            <p class="card-text">${element.description}</p>
                            <p class="card-text">Cantidad: ${element.quantity}</p>
                            <p class="card-text">Precio: ${element.price}</p>
                            <p class="card-text">Total: ${element.price * element.quantity}</p>
                            <a href="#" class="btn btn-primary">Comprar ahora</a>
                        </div>
                    </div>
                </li>
            `;
        });
 
        const current_items = document.querySelector(".items");
        current_items.innerHTML += html;
        start += limit;
    }
}).catch(function(error) {
    console.log(error);
});

La función fetch de JavaScript proporciona una interfaz para acceder y manipular partes del canal HTTP mediante peticiones y respuestas. Algo muy parecido a Ajax o XMLHttpRequest pero en versión moderna.

En este caso le pasamos un método «post» y un body con los parámetros que queremos trasladar al servidor.

Una vez enviado los datos, con then capturamos la respuesta del servidor.

Si la respuesta es correcta, retornamos la respuesta con json.

En caso contrario, mostraríamos al usuario un error de servidor.

Volvemos a usar then para recibir los datos del servidor, en este caso, los nuevos items o la variable booleana indicada.

Si no hemos llegado al fin, mostramos los elementos que llegan del servidor.

Código PHP

En el archivo ajax.php que se está invocando en el fetch tenemos lo siguiente:

try {
    $connexion = new PDO(
        "mysql:host=your-website.com;dbname=databasename",
        "usuario",
        "contraseña",
        array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
    );
 
} catch (PDOException $e){
    echo $e->getMessage();
}
 
$start = $_POST['start'];
$limit = $_POST['limit'];
 
try {
    $statement = $connexion->prepare(
        'SELECT *
        FROM products 
        ORDER BY products_id DESC 
        LIMIT '.(int)$start.','.(int)$limit
    );
 
    $statement->setFetchMode(PDO::FETCH_ASSOC);
    $statement->execute();
 
    $items = $statement->fetchAll();
 
    if (is_array($items) && count($items) > 0) {
        die(json_encode($items));
    } else {
        die(json_encode(array('reachedMax' => true)));
    }
} catch (PDOException $e){
    die(json_encode(array('error' => $e->getMessage())));
}

Hacemos un intento de conexión a la base de datos con PDO donde basededatos debe ser el nombre de tu base de datos, usuario debe ser el nombre de usuario de la base de datos y contraseña debe ser la contraseña para acceder a la base de datos.

Si se consigue conectar con la base de datos, recibimos los parámetros start y limit para intentar ejecutar la consulta que toque en función de estos parámetros.

Si la consulta arroja información, retornamos al JavaScript el array de elementos que toca mostrar.

Si la consulta arroja la variable endItems en true, se finaliza la ejecución y ahora la función getItems() no ejecutará la llamada asíncrona.

Ver demo Descargar

Conclusión

El scroll infinito puede ser un muy buen recurso para tu página web si se utiliza de la manera adecuada.

En según que tipo de proyectos es indispensable o requerido pero para otros puede ser opcional.

Basándome tan solo en sus ventajas e inconvenientes creo que vale la pena implementarlo.

¿Tu qué opinas?

Autor
Escrito por Jose Aguilar - Director ejecutivo y tecnológico en JA Modules. Experto programador PrestaShop y Experto programador WordPress.
Te ha servido? Valora esta entrada!
(1 votos, promedio: 5 de 5)
Comparte en las redes sociales
¿Buscas trabajo de programador?

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Ver más sobre