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:
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=10
Linguagem de código: JavaScript ( javascript )
A API aceita duas strings de consulta: page
e limit
. Essas strings de consulta permitem paginar as cotações do servidor.
As cotações são divididas nas páginas determinadas pela page
string de consulta. E cada página possui um número de cotações especificado pelo limit
parâ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 css
e js
.
Em segundo lugar, crie na style.css
pasta css
e app.js
na js
pasta.
Terceiro, crie um novo arquivo HTML index.html na infinite-scroll
pasta.
A estrutura final da pasta do projeto ficará assim:
Adicione código ao arquivo index.html
Abra o index.html
e 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.html
arquivo, coloque na style.css
seção da cabeça e app.js
na seção do corpo.
A seção body possui um div
com 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
div
com a classequotes
que 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 div
classe with quotes
e 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: page
e limit
. Ele usa a API Fetch para buscar dados da API.
Como fetch()
retorna uma promessa , você pode usar a await
sintaxe 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 await
palavra-chave, ela deve ser uma async
função.
A função showQuotes()
O seguinte define a showQuotes()
função que gera os <blockquote>
elementos do quotes
array e os anexa ao quotes
elemento:
// 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 quotes
array.
Para cada objeto quote, ele cria o <blockquote>
elemento com a quote
classe:
<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 quotesEl
elemento 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 .show
classe define a opacidade do indicador de carregamento como 1, o que o tornará visível.
Para ocultar o indicador de carregamento, remova a show
classe do elemento indicador de carregamento. Da mesma forma, para mostrar o indicador de carregamento, você adiciona a show
turma à sua lista de turmas.
Definir variáveis de controle
O seguinte declara a currentPage
variá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 currentPage
variá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 total
variá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 true
se:
- É 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 currentPage
variá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.js
arquivo em um IIFE .
A final app.js
ficará 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 .