O que é Rolagem Infinita?
A rolagem infinita é um recurso usado para carregar dinamicamente mais conteúdo em uma página quando o usuário rola até o final da página.
O conceito de rolagem infinita é usado para carregar dados de um servidor de uma maneira que pareça “sem problemas” para um usuário, mas não sobrecarrega o servidor solicitando muitos dados de uma só vez.
Em um tutorial anterior, implementamos um recurso de paginação que nos permitiu dividir nosso conteúdo em seções navegáveis conhecidas como páginas. Este tutorial usará uma implementação semelhante.
Benefícios do JavaScript Vanilla
Um benefício significativo de usar JavaScript é que nossa implementação é agnóstica de framework, ou seja, não depende de nenhum framework, então pode ser modificada para funcionar em todos eles.
Além disso, como estamos construindo o recurso nós mesmos e não dependendo de um plugin, podemos garantir que a implementação seja leve e perfeitamente adequada às nossas necessidades.
Aqui está uma olhada no produto final, role até a parte inferior da caneta para carregar mais conteúdo:
1. Marcação com HTML
Começaremos colocando o recipiente para nossos cartões na página. Adicionaremos os cartões ao contêiner usando JavaScript para que o div fique vazio.
Também temos carregador div
para exibir uma animação antes de adicionar o próximo lote de cartões e um cartão de ações div
para mostrar a contagem de cartas e o total de cartas.
Showing of cards
2. Estilizando com CSS
Os cartões que adicionaremos ao div do contêiner de cartão terão um nome de classe de ‘card’.
#card-container { display: flex; flex-wrap: wrap; } .card { height: 55vh; width: calc((100% / 3) - 16px); margin: 8px; border-radius: 3px; transition: all 200ms ease-in-out; display: flex; align-items: center; justify-content: center; } .card:hover { box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); } .card-actions { margin: 8px; padding: 16px 0; display: flex; justify-content: space-between; align-items: center; }
Também criaremos uma animação de carregamento para os cartões de esqueleto na div do carregador, animando o ::after
pseudo-seletor:
#loader { display: flex; } .skeleton-card { height: 55vh; width: calc((100% / 3) - 16px); margin: 8px; border-radius: 3px; transition: all 200ms ease-in-out; position: relative; background-color: #eaeaea; } .skeleton-card::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; left: 0; transform: translateX(-100%); background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, 0.2) 20%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0)); animation: load 1s infinite; } @keyframes load { 100% { transform: translateX(100%); } }
Estilo acessível
Sempre que incluímos uma animação em uma página da Web, é importante considerar as implicações de acessibilidade. Alguns usuários podem preferir não ter nenhuma animação e podemos levar essa preferência em consideração em nosso estilo usando a regra de mídia, prefers-reduced-motion
@media screen and (prefers-reduced-motion: reduce) { .skeleton-card::after { animation: none; } }
3. Funcionalidade com JavaScript
Vamos quebrar a lógica por trás da rolagem infinita.
- Defina o limite do conteúdo a ser carregado na página.
- Detecte quando o usuário atingiu o final do contêiner de conteúdo.
- Carregue mais conteúdo quando o final do contêiner for atingido.
- Se não houver mais conteúdo a ser carregado, pare a rolagem infinita.
Definindo Constantes
Primeiro, vamos pegar todos os elementos que precisaremos do nosso DOM:
const cardContainer = document.getElementById("card-container"); const cardCountElem = document.getElementById("card-count"); const cardTotalElem = document.getElementById("card-total"); const loader = document.getElementById("loader");
Agora precisamos definir nossas variáveis globais.
Precisaremos de um valor para o número máximo de cartões a serem adicionados à página. Se você estiver obtendo seus dados de um servidor, esse valor será o comprimento da resposta do servidor. Vamos inicializar um limite de cartão de 99.
const cardLimit = 99;
o cardTotalElem
é o elemento para exibir o número máximo de cartões na página para que possamos definir o innerHTML
para o cardLimit
valor;
cardTotalElem.innerHTML = cardLimit;
Em seguida, definiremos uma variável para quantos cartões queremos aumentar a página:
const cardIncrease = 9;
Queremos saber quantas “páginas” teremos, ou seja, quantas vezes podemos aumentar o conteúdo até atingirmos o limite máximo. Por exemplo, com nosso definido cardLimit
e cardIncrease
variáveis, podemos aumentar o conteúdo 10 vezes (assumindo que já carregamos os primeiros 9 elementos) até atingirmos o limite. Faremos isso dividindo o cardLimit
pelo cardIncrease
.
const pageCount = Math.ceil(cardLimit / cardIncrease);
Em seguida, definiremos um valor para determinar em qual página estamos:
let currentPage = 1;
Criando um novo cartão
Agora que temos todas as nossas constantes, vamos fazer uma função para adicionar um novo cartão ao container de cartões. Vamos definir o innerHTML
dos nossos cartões ao valor do índice para que possamos acompanhar o número de cartões que estamos adicionando.
Um recurso divertido nesta demonstração é que cada cartão tem uma cor de fundo gerada aleatoriamente.
const getRandomColor = () => { const h = Math.floor(Math.random() * 360); return `hsl(${h}deg, 90%, 85%)`; }; const createCard = (index) => { const card = document.createElement("div"); card.className = "card"; card.innerHTML = index; card.style.backgroundColor = getRandomColor(); cardContainer.appendChild(card); };
Adicionando cartões ao contêiner
Agora adicionaremos nossos cartões ao nosso contêiner usando uma funcionalidade semelhante ao tutorial de paginação.
Primeiro, determine o intervalo de cartões a serem adicionados à página. o addCards
função aceitará um pageIndex
parâmetro, que irá atualizar o global currentPage
valor. Se estivermos na página 1, adicionaremos os cartões de 1 a 9. Se estivermos na página 2, adicionaremos os cartões de 10 a 18 e assim por diante.
Podemos definir isso matematicamente como:
const addCards = (pageIndex) => { currentPage = pageIndex; const startRange = (pageIndex - 1) * cardIncrease; const endRange = pageIndex * cardIncrease; for (let i = startRange + 1; i <= currRange; i++) { createCard(i); } };
Nesta função, nosso intervalo inicial será sempre um a menos que o valor que estamos tentando obter (ou seja, na página 1, o intervalo inicial é 0, na página 2, o intervalo inicial é 9), portanto, consideraremos isso definindo o valor do nosso índice de loop for para startRange + 1
.
Detectando quando o limite do cartão é atingido
Um limite que teremos que observar é o endRange
número. Se estivermos na última página, queremos que nosso intervalo final seja o mesmo que o cardLimit
. Por exemplo, se tivermos um cardLimit
de 75 e um cardIncrease
de 10 e estamos na página 8, nosso índice inicial será 70 e nosso endRange
valor deve ser 75.
Vamos modificar nosso addCards
função para dar conta disso:
const addCards = (pageIndex) => { currentPage = pageIndex; const startRange = (pageIndex - 1) * cardIncrease; const endRange = currentPage == pageCount ? cardLimit : pageIndex * cardIncrease; for (let i = startRange + 1; i <= endRange; i++) { createCard(i); } };
Nossa demonstração também inclui um cardTotal
elemento que exibe o número de cartões que estão sendo mostrados na página, então definiremos o innerHTML
deste elemento como o intervalo final.
const addCards = (pageIndex) => { currentPage = pageIndex; const startRange = (pageIndex - 1) * cardIncrease; const endRange = currentPage == pageCount ? cardLimit : pageIndex * cardIncrease; cardCountElem.innerHTML = endRange; for (let i = startRange + 1; i <= endRange; i++) { createCard(i); } };
Carregando cartões iniciais
Definimos um recurso para adicionar cartões ao contêiner para incluir um window.onload
função para definir os cartões iniciais a serem adicionados à página.
window.onload = function () { addCards(currentPage); };
Manipulando a rolagem infinita
Vamos lidar com nossa rolagem infinita aumentando o currentPage
número para adicionar novos cartões ao contêiner quando chegarmos ao final da página. Podemos detectar quando o final da página é alcançado adicionando o innerHeight
da janela para o valor de rolagem pageYOffset
e comparando com o documento offsetHeight
que é a altura total da página.
Aqui está uma representação visual de como isso se parece:
Quando chegamos ao final da página, queremos carregar uma nova página chamando nosso addCards
função com currentPage + 1.
const handleInfiniteScroll = () => { const endOfPage = window.innerHeight + window.pageYOffset >= document.body.offsetHeight; if (endOfPage) { addCards(currentPage + 1); } };
Em seguida, criamos um ouvinte de eventos para a rolagem da janela e passamos nossa função acima para ele:
window.addEventListener("scroll", handleInfiniteScroll);
Otimização de desempenho
Como estamos trabalhando com o ouvinte de eventos de rolagem, é benéfico para o desempenho de nossa página da Web limitar o número de chamadas feitas. Podemos diminuir o número de chamadas usando uma função de aceleração.
Vamos definir nossa função de aceleração desta forma:
var throttleTimer; const throttle = (callback, time) => { if (throttleTimer) return; throttleTimer = true; setTimeout(() => { callback(); throttleTimer = false; }, time); };
e então passamos a função do acelerador para o handleInfiniteScroll
função
const handleInfiniteScroll = () => { throttle(() => { const endOfPage = window.innerHeight + window.pageYOffset >= document.body.offsetHeight; if (endOfPage) { addCards(currentPage + 1); } }, 1000); };
Parando a rolagem infinita
Neste ponto, configuramos nossas funções para adicionar mais conteúdo quando o final da página for atingido. Agora, vamos garantir que nossa função pare de ser executada quando não houver mais conteúdo a ser adicionado, ou seja, quando o cardLimit
é atingido.
Primeiro, vamos definir nosso removeInfiniteScroll
função. Nesta função, vamos remover o handleInfiniteScroll
função do ouvinte de eventos de rolagem e também exclua o div do carregador.
const removeInfiniteScroll = () => { loader.remove(); window.removeEventListener("scroll", handleInfiniteScroll); };
Agora vamos modificar nosso handleInfiniteScroll
para contabilizar se não houver mais conteúdo a ser adicionado, ou seja, estamos na última página de conteúdo.
const handleInfiniteScroll = () => { throttle(() => { const endOfPage = window.innerHeight + window.pageYOffset >= document.body.offsetHeight; if (endOfPage) { addCards(currentPage + 1); } if (currentPage === pageCount) { removeInfiniteScroll(); } }, 1000); };
Conclusão
E aí temos que! Construímos uma implementação acessível e de alto desempenho do recurso de rolagem infinita. Confira o código JavaScript completo clicando no botão JS guia na demonstração incorporada abaixo:
Originally posted 2022-07-09 09:06:23.