Rolagem infinita de JavaScript

Resumo : neste tutorial, você aprenderá como implementar o recurso de rolagem infinita do JavaScript.

O que você vai construir

A imagem a seguir ilustra o aplicativo web que você irá construir:

Aplicativo de rolagem infinita JavaScript

A página exibirá uma lista de cotações provenientes de uma API. Por padrão, mostra 10 cotações.

Se você rolar até o final da página, o aplicativo da web exibirá um indicador de carregamento. Além disso, ele chamará a API para buscar mais cotações e anexá-las à lista atual.

A URL da API que você usará é a seguinte:

https://api.tutorials.acervolima.com/v1/quotes/?page=1&limit=10Linguagem de código:  JavaScript  ( javascript )

A API aceita duas strings de consulta: pagee limit. Essas strings de consulta permitem paginar as cotações do servidor.

As cotações são divididas nas páginas determinadas pela pagestring de consulta. E cada página possui um número de cotações especificado pelo limitparâmetro.

Clique aqui para ver o aplicativo web final que usa o recurso de rolagem infinita do JavaScript.

Crie uma estrutura de projeto

Primeiro, crie uma nova pasta chamada infinite-scroll. Dentro dessa pasta, crie duas subpastas csse js.

Em segundo lugar, crie na style.csspasta csse app.jsna jspasta.

Terceiro, crie um novo arquivo HTML index.html na infinite-scrollpasta.

A estrutura final da pasta do projeto ficará assim:

Adicione código ao arquivo index.html

Abra o index.htmle adicione o seguinte código a ele:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript Infinite Scroll - Quotes</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>

    <div class="container">
        <h1>Programming Quotes</h1>

        <div class="quotes">
        </div>

        <div class="loader">
            <div></div>
            <div></div>
            <div></div>
        </div>
    </div>
    <script src="js/app.js"></script>
</body>
</html>Linguagem de código:  HTML, XML  ( xml )

No index.htmlarquivo, coloque na style.cssseção da cabeça e app.jsna seção do corpo.

A seção body possui um divcom o nome da classe container. O elemento contêiner possui quatro elementos filhos:

  • Um título (h1) que mostra o título da página.
  • A divcom a classe quotesque será o elemento pai de todas as aspas.
  • Um carregador que exibe o indicador de carregamento. Por padrão, o indicador de carregamento fica invisível.

Fazendo o app.js

O seguinte usa o querySelector()para selecionar a divclasse with quotese o loader.

const quotesEl = document.querySelector('.quotes');
const loader = document.querySelector('.loader');Linguagem de código:  JavaScript  ( javascript )

A função getQuotes()

A getQuotes()função a seguir chama a API e retorna as aspas:

const getQuotes = async (page, limit) => {
    const API_URL = `https://api.tutorials.acervolima.com/v1/quotes/?page=${page}&limit=${limit}`;
    const response = await fetch(API_URL);
    // handle 404
    if (!response.ok) {
        throw new Error(`An error occurred: ${response.status}`);
    }
    return await response.json();
}Linguagem de código:  JavaScript  ( javascript )

A getQuotes()função aceita dois argumentos: pagee limit. Ele usa a API Fetch para buscar dados da API.

Como fetch()retorna uma promessa , você pode usar a awaitsintaxe para obter a resposta. E você chama o json()método do objeto de resposta para obter os dados JSON.

O getQuotes()retorna uma promessa que será resolvida para os dados JSON.

Como a getQuotes()função usa a awaitpalavra-chave, ela deve ser uma asyncfunção.

A função showQuotes()

O seguinte define a showQuotes()função que gera os <blockquote>elementos do quotesarray e os anexa ao quoteselemento:

// show the quotes
const showQuotes = (quotes) => {
    quotes.forEach(quote => {
        const quoteEl = document.createElement('blockquote');
        quoteEl.classList.add('quote');

        quoteEl.innerHTML = `
            <span>${quote.id})</span>
            ${quote.quote}
            <footer>${quote.author}</footer>
        `;

        quotesEl.appendChild(quoteEl);
    });
};Linguagem de código:  JavaScript  ( javascript )

Como funciona:

O showQuotes()usa o forEach()método para iterar sobre o quotesarray.

Para cada objeto quote, ele cria o <blockquote>elemento com a quoteclasse:

<blockquote class="quote">
</blockquote>Linguagem de código:  HTML, XML  ( xml )

E gera a representação HTML de um objeto de cotação usando a sintaxe literal do modelo . Ele adiciona o HTML ao <blockquote>elemento.

O seguinte mostra um exemplo do <blockquote>elemento gerado:

<blockquote class="quote">
   <span>1)</span>
      Talk is cheap. Show me the code.
    <footer>Linus Torvalds</footer>
</blockquote>Linguagem de código:  HTML, XML  ( xml )

No final de cada iteração, a função anexa o <blockquote>elemento aos elementos filhos do quotesElelemento usando o appendChild()método.

Mostrar/ocultar funções do indicador de carregamento

A seguir são definidas duas funções que mostram e ocultam o elemento indicador de carregamento:

const hideLoader = () => {
    loader.classList.remove('show');
};

const showLoader = () => {
    loader.classList.add('show');
};Linguagem de código:  JavaScript  ( javascript )

O indicador de carregamento tem opacidade 0, que é invisível por padrão. A .showclasse define a opacidade do indicador de carregamento como 1, o que o tornará visível.

Para ocultar o indicador de carregamento, remova a showclasse do elemento indicador de carregamento. Da mesma forma, para mostrar o indicador de carregamento, você adiciona a showturma à sua lista de turmas.

Definir variáveis ​​de controle

O seguinte declara a currentPagevariável e inicializa-a como um:

 let currentPage = 1;Linguagem de código:  JavaScript  ( javascript )

Ao rolar para baixo até o final da página, o aplicativo fará uma solicitação de API para obter as próximas cotações. Antes de fazer isso, você precisa aumentar a currentPagevariável em um.

Para especificar o número de cotações que você deseja buscar por vez, você pode usar uma constante como esta:

const limit = 10;Linguagem de código:  JavaScript  ( javascript )

A totalvariável a seguir armazena o total de cotações retornadas da API:

let total = 0;Linguagem de código:  JavaScript  ( javascript )

A função hasMoreQuotes()

A seguinte hasMoreQuotes()função retorna truese:

  • É a primeira busca ( total === 0)
  • Ou há mais cotações para buscar na API ( startIndex< total)
const hasMoreQuotes = (page, limit, total) => {
    const startIndex = (page - 1) * limit + 1;
    return total === 0 || startIndex < total;
};Linguagem de código:  JavaScript  ( javascript )

A função loadQuotes()

O seguinte define uma função que executa quatro ações:

  • Mostre o indicador de carregamento.
  • Obtenha as cotações da API chamando a getQuotes()função se houver mais cotações para buscar.
  • Mostre as citações na página.
  • Oculte o indicador de carregamento.
// load quotes
const loadQuotes = async (page, limit) => {
    // show the loader
    showLoader();
    try {
        // if having more quotes to fetch
        if (hasMoreQuotes(page, limit, total)) {
            // call the API to get quotes
            const response = await getQuotes(page, limit);
            // show quotes
            showQuotes(response.data);
            // update the total
            total = response.total;
        }
    } catch (error) {
        console.log(error.message);
    } finally {
        hideLoader();
    }
};Linguagem de código:  JavaScript  ( javascript )

Se a getQuotes()função for executada muito rapidamente, você não verá o indicador de carregamento.

Para garantir que o indicador de carregamento esteja sempre aparecendo, você pode usar a setTimeout()função:

// load quotes
const loadQuotes = async (page, limit) => {

    // show the loader
    showLoader();

    // 0.5 second later
    setTimeout(async () => {
        try {
            // if having more quotes to fetch
            if (hasMoreQuotes(page, limit, total)) {
                // call the API to get quotes
                const response = await getQuotes(page, limit);
                // show quotes
                showQuotes(response.data);
                // update the total
                total = response.total;
            }
        } catch (error) {
            console.log(error.message);
        } finally {
            hideLoader();
        }
    }, 500);

};Linguagem de código:  JavaScript  ( javascript )

Ao adicionar a setTimeout()função, o indicador de carregamento será exibido por pelo menos meio segundo. E você pode ajustar o atraso alterando o segundo argumento da setTimeout()função.

Anexe o evento de rolagem

Para carregar mais cotações quando os usuários rolam até o final da página, você precisa anexar um manipulador de eventos de rolagem .

O manipulador de eventos scroll chamará a loadQuotes()função se as seguintes condições forem atendidas:

  • Primeiro, a posição de rolagem está na parte inferior da página.
  • Em segundo lugar, há mais cotações para buscar.

O manipulador de eventos scroll também aumentará a currentPagevariável antes de carregar as próximas cotações.

 window.addEventListener('scroll', () => {
    const {
        scrollTop,
        scrollHeight,
        clientHeight
    } = document.documentElement;

    if (scrollTop + clientHeight >= scrollHeight - 5 &&
        hasMoreQuotes(currentPage, limit, total)) {
        currentPage++;
        loadQuotes(currentPage, limit);
    }
}, {
    passive: true
});Linguagem de código:  JavaScript  ( javascript )

Inicialize a página

Quando a página carrega pela primeira vez, você precisa chamar a loadQuotes()função para carregar o primeiro lote de cotações:

loadQuotes(currentPage, limit);

Envolva o código app.js em um IIFE

Para evitar o conflito de variáveis ​​e funções que você definiu, você pode agrupar todo o código do app.jsarquivo em um IIFE .

A final app.jsficará assim:

(function () {

    const quotesEl = document.querySelector('.quotes');
    const loaderEl = document.querySelector('.loader');

    // get the quotes from API
    const getQuotes = async (page, limit) => {
        const API_URL = `https://api.tutorials.acervolima.com/v1/quotes/?page=${page}&limit=${limit}`;
        const response = await fetch(API_URL);
        // handle 404
        if (!response.ok) {
            throw new Error(`An error occurred: ${response.status}`);
        }
        return await response.json();
    }

    // show the quotes
    const showQuotes = (quotes) => {
        quotes.forEach(quote => {
            const quoteEl = document.createElement('blockquote');
            quoteEl.classList.add('quote');

            quoteEl.innerHTML = `
            <span>${quote.id})</span>
            ${quote.quote}
            <footer>${quote.author}</footer>
        `;

            quotesEl.appendChild(quoteEl);
        });
    };

    const hideLoader = () => {
        loaderEl.classList.remove('show');
    };

    const showLoader = () => {
        loaderEl.classList.add('show');
    };

    const hasMoreQuotes = (page, limit, total) => {
        const startIndex = (page - 1) * limit + 1;
        return total === 0 || startIndex < total;
    };

    // load quotes
    const loadQuotes = async (page, limit) => {

        // show the loader
        showLoader();

        // 0.5 second later
        setTimeout(async () => {
            try {
                // if having more quotes to fetch
                if (hasMoreQuotes(page, limit, total)) {
                    // call the API to get quotes
                    const response = await getQuotes(page, limit);
                    // show quotes
                    showQuotes(response.data);
                    // update the total
                    total = response.total;
                }
            } catch (error) {
                console.log(error.message);
            } finally {
                hideLoader();
            }
        }, 500);

    };

    // control variables
    let currentPage = 1;
    const limit = 10;
    let total = 0;


    window.addEventListener('scroll', () => {
        const {
            scrollTop,
            scrollHeight,
            clientHeight
        } = document.documentElement;

        if (scrollTop + clientHeight >= scrollHeight - 5 &&
            hasMoreQuotes(currentPage, limit, total)) {
            currentPage++;
            loadQuotes(currentPage, limit);
        }
    }, {
        passive: true
    });

    // initialize
    loadQuotes(currentPage, limit);

})();Linguagem de código:  JavaScript  ( javascript )

Aqui está a versão final do aplicativo web .

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *