civil-and-structural-engineering
Criando uma Galeria de Fotos Dinâmica com Filtros e Ordenação Usando Javascript
Table of Contents
Introdução
Construir uma galeria de fotos dinâmica com recursos de filtragem e classificação transforma uma coleção de imagens estáticas em uma experiência envolvente e amigável. Os visitantes podem encontrar rapidamente imagens que correspondam aos seus interesses – por exemplo, filtragem por natureza, cidade ou pessoas – e reordenar resultados por nome, data ou classificação sem um reload de página. Este artigo fornece uma abordagem abrangente e pronta para a produção de uma galeria como esta usando JavaScript simples, HTML e CSS. Você aprenderá como estruturar sua marcação, aplicar uma lógica eficiente de filtragem e classificação, melhorar o desempenho com carregamento preguiçoso e seguir as melhores práticas de acessibilidade. A galeria final será responsiva, sustentável e facilmente extensível.
Configurar a Estrutura HTML
Uma fundação HTML bem estruturada torna a filtragem e a ordenação simples. Cada elemento de imagem deve ter atributos personalizados que descrevem a sua categoria, nome, data ou qualquer outra propriedade que pretenda filtrar ou classificar.
Marcação de Base para Filtros e Controles de Ordenação
Criar um recipiente para botões de filtro e outro para controles de ordenação. Use elementos com ] e atributos:
<div id="controls">
<div id="filter-buttons" role="group" aria-label="Filter photos by category">
<button data-filter="all" class="active">Show All</button>
<button data-filter="nature">Nature</button>
<button data-filter="city">City</button>
<button data-filter="people">People</button>
</div>
<div id="sort-options" role="group" aria-label="Sort photos">
<button data-sort="name">Sort by Name</button>
<button data-sort="date">Sort by Date</button>
<button data-sort="rating">Sort by Rating</button>
</div>
</div>
Incluindo e melhora a acessibilidade para os usuários de leitores de tela. O botão está marcado com uma classe para indicar o estado inicial; você vai style isto com CSS.
Container da Galeria de Imagens
Dentro de um , coloque cada foto em seu próprio elemento de embalagem. Use , , , e atributos para filtragem e ordenação. Por exemplo:
<div id="gallery" class="photo-grid">
<div class="photo" data-category="nature" data-name="Sunset Over the Hills" data-date="2023-06-15" data-rating="4.5">
<img src="images/sunset.jpg" alt="Sunset over rolling hills" loading="lazy">
<div class="photo-caption">Sunset Over the Hills</div>
</div>
<div class="photo" data-category="city" data-name="Downtown Skyline" data-date="2023-07-01" data-rating="4.2">
<img src="images/skyline.jpg" alt="Downtown skyline at dusk" loading="lazy">
<div class="photo-caption">Downtown Skyline</div>
</div>
<!-- more photos -->
</div>
O atributo deteta o carregamento de imagens fora do ecrã, melhorando o desempenho inicial da carga da página. Cada embalagem de fotos pode também incluir uma legenda ou sobreposição para obter informações adicionais.
Usando Atributos de Dados Efetivamente
[[FLT: 0]] Atributos de dados[ (por exemplo, , ) não se limitam a strings. Para ordenação numérica, os números de armazenamento como strings; O JavaScript irá analisá- los conforme necessário. Para várias categorias, você pode armazenar uma lista separada por espaços como e dividi- la durante a filtragem. Esta técnica permite que as imagens apareçam sob vários filtros, uma funcionalidade que implementaremos mais tarde. Para uma referência abrangente sobre atributos de dados, veja a documentação [[FLT: 2]] MDN na API do conjunto de dados[[[FLT: 3]].
Estilhaçar a Galeria com CSS
Um layout limpo e responsivo define o palco para as funcionalidades interativas. Use o CSS Grid ou Flexbox para a grade de fotos e style os botões para indicar os filtros ativos e estado de ordenação.
Disposição da Grade de Fotos
.photo-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
padding: 1rem 0;
}
.photo {
position: relative;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.photo img {
width: 100%;
height: auto;
display: block;
transition: transform 0.3s ease;
}
.photo:hover img {
transform: scale(1.05);
}
Esta grade garante que as imagens se adaptam ao tamanho da tela. O efeito hover adiciona uma interação de zoom sutil, fazendo com que a galeria se sinta mais polida.
Estado ativo para botões
#filter-buttons button.active,
#sort-options button.active {
background-color: #007acc;
color: #fff;
border-color: #007acc;
}
button {
padding: 0.5rem 1rem;
border: 1px solid #ccc;
background: #fff;
cursor: pointer;
margin: 0.25rem;
border-radius: 4px;
transition: background 0.2s, color 0.2s;
}
button:hover {
background: #e6e6e6;
}
A aplicação da classe ao botão filtro/sorte atual fornece feedback visual. O JavaScript irá gerenciar a adição e remoção desta classe.
Considerações Responsivas
Certifique-se de que a galeria funciona em dispositivos de toque. Aumente o tamanho do alvo de toque do botão para pelo menos 44px por 44px (recomendação WCAG 2.1). Use consultas de mídia se necessário para mudar de uma grade multi-coluna para uma única coluna em telas muito pequenas.
Implementação de Filtro JavaScript
Agora, nós damos vida à galeria. A ideia principal: ouvir os cliques nos botões do filtro, então mostrar ou esconder elementos de foto com base no seu atributo .
Selecionar elementos DOM e Inicializar
const filterButtons = document.querySelectorAll('#filter-buttons button');
const sortButtons = document.querySelectorAll('#sort-options button');
const gallery = document.getElementById('gallery');
let photos = Array.from(gallery.children);
let activeFilter = 'all';
let activeSort = 'name'; // default sort
Armazenar como um array nos dá fácil acesso a métodos de array como e . Também acompanhamos a ordem de classificação e filtro atual para que possamos re-aplicar a ordenação após uma mudança de filtro.
Lógica de Filtragem
function filterPhotos(filter) {
activeFilter = filter;
photos.forEach(photo => {
const categories = photo.dataset.category; // may be a space-separated string
const shouldShow = filter === 'all' || categories.split(' ').includes(filter);
photo.style.display = shouldShow ? '' : 'none';
});
// After filtering, re-sort the visible photos
sortPhotos(activeSort);
}
Esta função suporta várias categorias: se , então escolher “natureza” ou “paisagem” mostrará a foto. Nota: retorna o valor de (como uma string). Usando ] lida com o caso multi-categoria.
Anexar os Ouvintes de Evento aos Botões de Filtro
filterButtons.forEach(button => {
button.addEventListener('click', () => {
const filter = button.dataset.filter;
// Update active class on filter buttons
filterButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
// Apply filter
filterPhotos(filter);
});
});
Removendo a classe de todos os botões e adicionando- a à tecla carregada, garante consistência visual. A função ] é chamada com o valor do filtro selecionado.
Implementação de Ordenação JavaScript
A ordenação reorganiza as fotos visíveis no DOM com base em um atributo escolhido (por exemplo, nome, data, classificação).
Função de Ordenação
function sortPhotos(sortBy) {
activeSort = sortBy;
// Get currently visible photos (display not 'none')
const visiblePhotos = photos.filter(photo => photo.style.display !== 'none');
visiblePhotos.sort((a, b) => {
let valA, valB;
switch (sortBy) {
case 'name':
valA = a.dataset.name.toLowerCase();
valB = b.dataset.name.toLowerCase();
return valA.localeCompare(valB);
case 'date':
valA = new Date(a.dataset.date);
valB = new Date(b.dataset.date);
return valA - valB;
case 'rating':
valA = parseFloat(a.dataset.rating);
valB = parseFloat(b.dataset.rating);
return valB - valA; // descending: highest first
default:
return 0;
}
});
// Re‑append sorted photos back to the gallery container
visiblePhotos.forEach(photo => gallery.appendChild(photo));
}
A ordenação funciona apenas em fotos visíveis, o que significa que após uma mudança de filtro você restaura a ordem de acordo com o tipo ativo. Para strings, usamos para a ordenação alfabética adequada. As datas são comparadas como objetos de Data, e as classificações são ordenadas em ordem decrescente (mais popular primeiro).
Ouvintes de eventos para botões de ordenação
sortButtons.forEach(button => {
button.addEventListener('click', () => {
const sortBy = button.dataset.sort;
sortButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
sortPhotos(sortBy);
});
});
Quando um botão de ordenação é clicado, atualizamos a classe ativa e chamamos com a chave de ordenação desejada. Porque já chama após a filtragem, a galeria permanece consistente.
Configuração Inicial
// Set default active buttons
document.querySelector('#filter-buttons [data-filter="all"]').classList.add('active');
document.querySelector('#sort-options [data-sort="name"]').classList.add('active');
// Load and initially sort by name
filterPhotos('all');
Chamar no início garante que a galeria seja povoada com todas as imagens e ordenada pelo tipo padrão (nome).
Filtragem e pesquisa avançadas
Um filtro de categoria simples é útil, mas poderá querer combinar vários filtros ou adicionar uma entrada de pesquisa de texto. As seguintes melhorias são criadas na lógica do núcleo.
Filtros de Categoria Múltiplas (Checkboxes)
Em vez de botões exclusivos, use caixas de seleção para que os usuários possam selecionar várias categorias:
<div id="filter-checkboxes">
<label><input type="checkbox" value="nature" checked> Nature</label>
<label><input type="checkbox" value="city" checked> City</label>
<label><input type="checkbox" value="people" checked> People</label>
</div>
Em seguida, modifique a lógica de filtragem para construir um conjunto de categorias ativas:
function filterPhotosByCheckboxes() {
const checked = document.querySelectorAll('#filter-checkboxes input:checked');
const activeCategories = Array.from(checked).map(cb => cb.value);
photos.forEach(photo => {
const photoCategories = photo.dataset.category.split(' ');
const shouldShow = activeCategories.length === 0 ||
photoCategories.some(cat => activeCategories.includes(cat));
photo.style.display = shouldShow ? '' : 'none';
});
sortPhotos(activeSort);
}
Se nenhuma caixa de seleção estiver selecionada, você pode optar por mostrar todas as imagens (como no código acima) ou não mostrar nenhuma —defina o UX desejado.
Entrada de Pesquisa de Texto
Adicionar um campo de entrada que procura legendas ou o atributo [[FLT: 45]]:
<input type="text" id="search" placeholder="Search photos...">
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', () => {
const query = searchInput.value.toLowerCase();
photos.forEach(photo => {
const name = photo.dataset.name.toLowerCase();
// Also search in caption if present
const caption = photo.querySelector('.photo-caption')?.innerText.toLowerCase() || '';
const matches = name.includes(query) || caption.includes(query);
// If a filter is active, also check category
const filter = activeFilter;
const catMatch = filter === 'all' || photo.dataset.category.split(' ').includes(filter);
photo.style.display = (matches && catMatch) ? '' : 'none';
});
sortPhotos(activeSort);
});
Combine a pesquisa com os botões de filtro para permitir que os resultados sejam mais limitados. Lembre- se que precisa de guardar o estado actual do filtro para o respeitar durante a pesquisa.
Desempenho e Acessibilidade
Uma galeria dinâmica deve ser rápida e utilizável por todos, incluindo pessoas que usam tecnologias assistivas.
Preguiçoso Carregando Imagens
Já usamos que descontinua o carregamento até que a imagem esteja próxima da viewport. Para navegadores mais antigos, você pode implementar um retrocesso JavaScript de carregamento preguiçoso usando a API . Isso garante que, mesmo que o carregamento preguiçoso nativo não seja suportado, as imagens fora da tela não são carregadas, reduzindo a largura de banda e melhorando o desempenho percebido.
Debuncing Search Input
Se você anexar o ouvinte de pesquisa a , ele dispara em cada tecla. Para grandes galerias, considere debouncar o manipulador (por exemplo, 200ms de atraso) para evitar manipulações excessivas do DOM. Um utilitário de debounecimento simples:
function debounce(func, delay) { let timeoutId; return function (...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } searchInput.addEventListener('input', debounce(handleSearch, 200));Keyboard Navigation
Filter and sort buttons should be focusable and operable via keyboard. Using native
<button>elements already provides keyboard interaction (Enter/Space). Ensure that after filtering or sorting, focus is managed logically; for example, you could move focus to the first photo after a filter change via a focusable element. Also, consider addingaria-pressedattributes to filter buttons to indicate toggle state.Announcing Changes to Screen Readers
Use an ARIA live region to announce filter and sort results:
<div id="gallery-announce" aria-live="polite" class="sr-only"></div>Após cada ação filtrar/sortar, atualize o texto desse elemento, por exemplo, “Mostrando 8 fotos da natureza ordenadas pelo nome”. Isso ajuda os usuários que dependem de leitores de tela a entender o que mudou.
CSS para conteúdo oculto
Em vez de usar sozinho, considere usar uma classe CSS como que esconde o elemento e o remove da árvore de acessibilidade:
.hidden { display: none !important; visibility: hidden; }Usando remove elementos da árvore de acessibilidade, o que é apropriado. Apenas certifique-se de que você não depende exclusivamente de sem porque isso deixa o elemento ocupando espaço.
Conclusão
Ao combinar HTML semântico limpo, CSS responsivo e JavaScript bem estruturado, você pode construir uma galeria de fotos dinâmica que seja rápida, acessível e agradável de usar. As técnicas cobertas – filtrando por categoria (incluindo várias categorias), classificando por vários atributos, adicionando pesquisa de texto e otimizando o desempenho – fornecem uma base sólida que pode ser estendida com recursos como paginação, rolagem infinita ou integração com uma API de backend.
Para leitura posterior, a documentação MDN em Array.prototype.sort()] explica o algoritmo de ordenação, e o web.dev responsive design guide oferece dicas de layout adicionais. Experimente com diferentes atributos de dados, animações e estilo personalizado para adaptar a galeria às necessidades do seu projeto. O resultado é um componente poderoso e interativo que coloca os usuários no controle de sua experiência de navegação.