Compreender os princípios básicos

Construir um gerenciador de favoritos com JavaScript e a API de armazenamento web é um excelente projeto para dominar conceitos fundamentais de front-end. No seu núcleo, a aplicação deve lidar com três operações primárias: criar, ler, e deletar[ — um padrão clássico CRUD, menos atualizações por enquanto. Os dados vivem no navegador []localStorage[[, permitindo que os favoritos persistam em sessões sem servidor.

Antes de escrever uma única linha de código, solidifique sua compreensão dos seguintes pilares:

  • A API DOM: Você irá consultar elementos, ouvir eventos e manipular a árvore de documentos para exibir os favoritos dinamicamente.
  • localStorage:] Esta loja de valor chave retém dados mesmo após o navegador estar fechado. Só suporta strings, por isso os objetos devem ser serializados com e deserializados com .
  • Programação orientada para eventos: Os formulários emitem eventos; apagar botões disparam eventos. Dominar não é negociável.
  • Métodos de array: , , e ajudarão a renderizar e manipular a lista de favoritos de forma eficiente.

Construindo o Gerenciador de Favoritos do Núcleo

Estrutura HTML

Comece com um esqueleto HTML semântico mínimo. O formulário recolhe o nome e URL do favorito; uma lista não ordenada mostra os favoritos armazenados.

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Bookmark Manager</title>
</head>
<body>
 <h1>My Bookmarks</h1>
 <form id="bookmarkForm">
 <label for="name">Name</label>
 <input type="text" id="name" required />
 <label for="url">URL</label>
 <input type="url" id="url" required />
 <button type="submit">Add Bookmark</button>
 </form>
 <ul id="bookmarkList"></ul>
 <script src="app.js" defer></script>
</body>
</html>

Observe o atributo na tag do script – garante que o DOM seja analisado totalmente antes de o script ser executado, eliminando a necessidade de um envoltório em configurações modernas.

Estilhaço para usabilidade (Opcional, mas Recomendado)

Embora o CSS não seja o foco, uma interface limpa melhora a experiência do usuário. Adicione uma folha de estilo simples para espaçar o formulário, dê uma aparência consistente aos botões e estile os itens da lista de favoritos com efeitos de hover. O estilo inline mínimo também pode ser injetado via JavaScript, mas uma opção separada é preferida para manutenção.

<!-- inside <head> -->
<link rel="stylesheet" href="style.css" />

Em , use flexbox para o layout do formulário, uma largura máxima para o recipiente e feedback visual distinto para excluir botões para evitar cliques acidentais.

Lógica JavaScript – O Coração da Aplicação

Toda a persistência e interatividade vivem em . As seções seguintes quebram cada função.

Inicialização dos Dados

Precisamos de uma variável central que mantenha a lista atual de favoritos. Ela deve ser inicializada de ou voltar para um array vazio.

let bookmarks = [];

function loadBookmarks() {
 const stored = localStorage.getItem('bookmarks');
 if (stored) {
 bookmarks = JSON.parse(stored);
 } else {
 bookmarks = [];
 }
}

function saveBookmarks() {
 localStorage.setItem('bookmarks', JSON.stringify(bookmarks));
}

loadBookmarks();

A função é chamada sempre que o array muda — após adicionar, editar ou excluir um marcador. Isto garante que o armazenamento esteja sempre sincronizado com o array in-memory.

Mostrar Favoritos

Renderizar a lista de favoritos significa iterar sobre o array e criar itens de lista com uma marca âncora e um botão de exclusão.

function renderBookmarks() {
 const list = document.getElementById('bookmarkList');
 list.innerHTML = ''; // clear existing entries

 bookmarks.forEach(function(bookmark, index) {
 const li = document.createElement('li');
 li.dataset.index = index;

 const link = document.createElement('a');
 link.href = bookmark.url;
 link.textContent = bookmark.name;
 link.target = '_blank';
 link.rel = 'noopener noreferrer';

 const deleteBtn = document.createElement('button');
 deleteBtn.textContent = 'Delete';
 deleteBtn.addEventListener('click', function() {
 deleteBookmark(index);
 });

 li.appendChild(link);
 li.appendChild(deleteBtn);
 list.appendChild(li);
 });
}

Usando em vez de innerHTML evita vulnerabilidades XSS quando os nomes dos favoritos contêm HTML. O botão excluir usa um fechamento para capturar o índice do marcador.

Adicionar um Marcador

Ouça o evento , evite o reload da página padrão, crie um objeto de favoritos, empurre-o para o array, persista e re-render.

document.getElementById('bookmarkForm').addEventListener('submit', function(e) {
 e.preventDefault();

 const nameInput = document.getElementById('name');
 const urlInput = document.getElementById('url');

 const newBookmark = {
 name: nameInput.value.trim(),
 url: urlInput.value.trim()
 };

 // Basic validation: ensure URL starts with http/https
 if (!newBookmark.url.startsWith('http://') && !newBookmark.url.startsWith('https://')) {
 newBookmark.url = 'https://' + newBookmark.url;
 }

 bookmarks.push(newBookmark);
 saveBookmarks();
 renderBookmarks();

 // Reset form
 nameInput.value = '';
 urlInput.value = '';
 nameInput.focus();
});

Esta abordagem é simples. Para a produção, você pode querer validar o formato URL ainda mais usando construtor ou um regex.

Excluindo um marcador

A exclusão remove o item no índice e atualiza o armazenamento e o DOM.

function deleteBookmark(index) {
 bookmarks.splice(index, 1);
 saveBookmarks();
 renderBookmarks();
}

Usando muda o array no lugar. Se você preferir imutabilidade, você pode usar e reatribuir , mas para um pequeno projeto como este, é claro e performante.

Melhorar a Aplicação

Uma vez que o CRUD básico funcione, considere essas melhorias para transformar um protótipo em uma ferramenta robusta.

Editar Favoritos

Substituir o nome/link estático por um modo de edição em linha. Quando o usuário clicar em um botão de edição, troque a etiqueta âncora com os campos de entrada pré- preenchidos com os valores atuais. Ao salvar, atualize o array e persista.

Dica de implementação: adicione uma função que cria entradas editáveis. Use delegação de eventos na lista para lidar com salvar edições sem anexar vários ouvintes.

Categorização com etiquetas

Adicione uma propriedade opcional a cada objeto de favoritos (por exemplo, ]). Então, estenda a interface com uma entrada de filtro que esconde itens de lista cujas etiquetas não correspondem. Você pode armazenar tags como uma string separada por vírgulas dentro do formulário e dividi-las em um array.

Importação e Exportação

Permitir que os usuários façam backup ou transfiram os favoritos. Use um ou um download de arquivo. Exportar serializa em uma string JSON e ativa um download via ] e . Importar lê o JSON e se funde com os favoritos existentes.

function exportBookmarks() {
 const data = JSON.stringify(bookmarks, null, 2);
 const blob = new Blob([data], { type: 'application/json' });
 const url = URL.createObjectURL(blob);
 const a = document.createElement('a');
 a.href = url;
 a.download = 'bookmarks.json';
 a.click();
 URL.revokeObjectURL(url);
}

Procurar e Filtrar

Adicionar uma entrada acima da lista de favoritos. Em cada evento , filtre o array pelo nome (ou URL) e chame uma variante de que exibe apenas as correspondências. Para evitar perder a lista original, guarde uma cópia filtrada ou use um parâmetro calculado.

Compatibilidade com o Teste e o Navegador

O armazenamento local é suportado em todos os navegadores modernos, mas versões mais antigas do Internet Explorer (IE 8+) tinham uma API diferente. Se você deve suportar ambientes legados, teste com polifills ou voltar para cookies. Hoje Chrome, Firefox, Safari, Edge (tanto Chromium quanto legado) manusear ] e ] sem problemas.

Ao testar, verifique:

  • Os dados sobrevivem às atualizações da página e o navegador reinicia.
  • Excluindo um favorito atualiza tanto a UI quanto o armazenamento.
  • Os caracteres especiais em nomes de favoritos (quotas, ampersands) são renderizados corretamente.
  • URLs com e sem são normalizadas.

Use as ferramentas de desenvolvimento [[FLT: 0][[FLT: 1]] & gt; Aplicação & gt; Armazenamento Local & gt; para inspecionar os dados salvos manualmente.[[ FLT: 2]] Para testes automatizados, considere usar [[ FLT: 3]] Cypress [[ FLT: 4]] ou [[ FLT: 5] Playwright[[[[ FLT: 6]] para simular fluxos de trabalho do usuário — preencher o formulário, adicionar, excluir, recarregar — e afirmar que a lista persiste.

Conclusão

Este projeto demonstra como algumas dezenas de linhas de baunilha JavaScript pode criar uma aplicação web totalmente funcional e persistente. Você aprendeu a aproveitar a localStorage API para persistência de dados, ] delegação de eventos[ para atualizações de UI eficientes, e operações CRUD[] sem uma infraestrutura. O padrão que você aplicou — inicializando estado de armazenamento, mutando estado através de funções, e re-renderizando o DOM — é a base de muitos frameworks de front-end modernos como React ou Vue.

Para aprofundar a sua compreensão, explore a documentação MDN sobre o armazenamento local e leia sobre ] o tratamento de eventos no DOM. Para uma gestão mais avançada do estado, consulte IndexedDB[] para conjuntos de dados maiores ou trabalhadores de serviços[[]] para experiências offline. Com estes blocos de construção, você pode agora expandir o seu gerenciador de favoritos para uma base de conhecimento pessoal completa.