Construir uma aplicação de calendário personalizada é uma excelente maneira de aprofundar a sua compreensão do JavaScript, do Modelo de Objeto de Documento do navegador (DOM) e da persistência de dados do lado do cliente. Ao aproveitar a API de Armazenamento Web — especificamente Armazenamento Local — você pode criar um calendário totalmente funcional e orientado para eventos que é executado inteiramente no navegador sem precisar de um servidor de infraestrutura ou banco de dados. Este tutorial lhe acompanha em cada passo, desde estruturar o HTML até implementar recursos avançados como o gerenciamento de eventos de arrastar e soltar.

Por que criar um calendário personalizado?

Bibliotecas de calendário pré-construídas (como FullCalendar ou DayPilot) oferecem soluções rápidas, mas construir uma do zero lhe dá controle completo sobre a interface do usuário, o tratamento de dados e o desempenho. Você também ganha experiência prática com conceitos de JavaScript como o objeto , delegação de eventos e a API . O aplicativo resultante pode ser estendido em uma ferramenta de gerenciamento de projetos, um sistema de reservas ou um diário pessoal.

Configurar a Estrutura HTML

Comece com um esqueleto HTML limpo. O calendário precisa de três componentes principais: uma barra de navegação (para alterar meses), um recipiente de grade (para células de dia) e um formulário de entrada de eventos. Use [[FLT: 2]] elementos com nomes de classes semânticos para um estilo e script fáceis.

<div id="calendar">
 <div class="calendar-header">
 <button id="prevBtn">&larr;</button>
 <h2 id="monthYear"></h2>
 <button id="nextBtn">&rarr;</button>
 </div>
 <div class="calendar-grid"></div>
 <div class="event-form">
 <input type="text" id="eventInput" placeholder="Add an event..." />
 <button id="saveEvent">Save</button>
 </div>
</div>

O será povoado dinamicamente pelo JavaScript. Para um layout amigável para dispositivos móveis, considere usar uma grade CSS de 7 colunas (uma para cada dia da semana). Reserve a primeira linha para nomes de dias (Sun-Sat).

Estilhar o calendário com CSS

CSS limpo e responsivo transforma o HTML em uma interface utilizável. Use uma grade CSS para a grade de calendário, configurando . Adicione espaçadores para dias antes do primeiro do mês. Para acessibilidade, garanta contraste de cores suficiente e inclua estilos em elementos interativos. Uma folha de estilo mínima é mostrada abaixo (inline ou vinculada).

.calendar-grid {
 display: grid;
 grid-template-columns: repeat(7, 1fr);
 gap: 2px;
}
.day-cell {
 min-height: 80px;
 border: 1px solid #ccc;
 padding: 4px;
 position: relative;
}
.day-cell.today {
 background-color: #eef;
}
.event {
 font-size: 0.8em;
 background: #4caf50;
 color: #fff;
 padding: 2px 4px;
 margin: 1px 0;
 border-radius: 3px;
 cursor: pointer;
}

Use consultas de mídia para reduzir o tamanho da célula em telas estreitas, e considere ocultar texto de evento e mostrar apenas uma contagem.

JavaScript Principal: Gerando a grade de calendário

Toda a dinâmica de renderização vive no JavaScript. A função central, , calcula o primeiro dia do mês e o número total de dias. Use para obter o índice do dia da semana (0 = domingo). Então gere células em um loop de 1 para o último dia do mês.

Trabalhando com o objeto Data

O objeto é a espinha dorsal da lógica do calendário. Para obter o último dia de um mês, use (o dia 0 do mês seguinte dá o último dia do mês atual). Guarde o mês e o ano atuais em variáveis globais para que a navegação possa atualizá- las.

Construindo a Grade

function renderCalendar() {
 const grid = document.querySelector('.calendar-grid');
 grid.innerHTML = '';

 const firstDay = new Date(currentYear, currentMonth, 1).getDay();
 const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();

 // Add empty cells for days before the 1st
 for (let i = 0; i < firstDay; i++) {
 const empty = document.createElement('div');
 empty.className = 'day-cell empty';
 grid.appendChild(empty);
 }

 // Generate day cells
 for (let day = 1; day <= daysInMonth; day++) {
 const cell = document.createElement('div');
 cell.className = 'day-cell';
 cell.dataset.date = `${currentYear}-${currentMonth + 1}-${day}`;

 const dateSpan = document.createElement('span');
 dateSpan.textContent = day;
 cell.appendChild(dateSpan);

 // Highlight today
 const today = new Date();
 if (currentYear === today.getFullYear() && currentMonth === today.getMonth() && day === today.getDate()) {
 cell.classList.add('today');
 }

 // Load events for this date
 loadEvents(cell);

 grid.appendChild(cell);
 }
}

Atualizar a exibição mês/ano no cabeçalho:

Anexar os ouvintes de eventos de clique aos botões Anterior e Próximo. Incremento ou decremento , ajustando o ano se necessário (por exemplo, após dezembro chegar a janeiro do próximo ano). Depois de atualizar as variáveis, ligue novamente .

document.getElementById('prevBtn').addEventListener('click', () => {
 currentMonth--;
 if (currentMonth < 0) {
 currentMonth = 11;
 currentYear--;
 }
 renderCalendar();
});

document.getElementById('nextBtn').addEventListener('click', () => {
 currentMonth++;
 if (currentMonth > 11) {
 currentMonth = 0;
 currentYear++;
 }
 renderCalendar();
});

Para uma usabilidade extra, adicione um botão Hoje que redefiniu a visualização para o mês atual e destaca o dia atual.

Guardar os Eventos do & com Armazenamento Local

[[FLT: 0]] Armazenamento Local[[FLT: 1]] fornece uma simples chave- valor de armazenamento que sobrevive ao navegador reinicia. Use um padrão de chave consistente, por exemplo, [FLT: 17]], armazenando arrays JSON de objetos de evento. Inclua propriedades como [[FLT: 18]], [[FLT: 19]], [[FLT: 20]], e [[FLT: 21]].

Gravar um Novo Evento

Quando o usuário clicar no botão "Salvar", capture o valor de entrada e a data atualmente selecionada. (Você pode adicionar um seletor de data ou detectar qual célula de dia é clicada.) Recuperar quaisquer eventos existentes para essa data do Armazenamento Local, pressione o novo evento e, em seguida, salve de volta.

function saveEvent(dateKey, eventText) {
 const existing = JSON.parse(localStorage.getItem(dateKey)) || [];
 existing.push({ id: Date.now(), text: eventText, time: new Date().toLocaleTimeString() });
 localStorage.setItem(dateKey, JSON.stringify(existing));
 renderCalendar(); // refresh to show new event
}

Carregando eventos em células diurnas

Dentro , para cada célula não-vazio dia, chamar uma função que consulta Armazenamento Local para essa chave de data. Se os eventos existem, passar por eles e adicionar elementos para a célula.

function loadEvents(cell) {
 const dateKey = cell.dataset.date;
 const events = JSON.parse(localStorage.getItem(dateKey));
 if (!events) return;

 events.forEach(evt => {
 const eventDiv = document.createElement('div');
 eventDiv.className = 'event';
 eventDiv.textContent = evt.text;
 eventDiv.dataset.id = evt.id;
 // Optional: add a delete button
 cell.appendChild(eventDiv);
 });
}

Excluindo e Edição de Eventos

Para excluir, anexe um evento de clique a cada elemento de evento (ou use a delegação de eventos). Recupere o array para essa data, filtre o evento pelo seu , e salve o array atualizado de volta ao Armazenamento Local. A edição pode ser feita clicando duas vezes no evento, solicitando um novo texto e atualizando o array.

Recursos avançados para melhorar a funcionalidade

Uma vez que o calendário básico está funcionando, você pode adicionar recursos que melhoram significativamente a experiência do usuário.

Eventos de Codificação de Cores por Tipo

Permitir que os usuários atribuam categorias (por exemplo, trabalho, pessoal, saúde). Armazene um campo no Armazenamento Local. Em CSS, defina classes como , e aplique-as dinamicamente.

Reagendamento de arrasto e de descarga

Use a API Arrastar e Soltar HTML5 para mover os eventos entre as células do dia. Quando um evento é deixado cair em um dia diferente, atualize a chave de data no Armazenamento Local: remova o evento do seu array de data original e empurre-o para o array da nova data.

Eventos recorrentes (Semana/Mês)

Adicione uma opção "Repetir" ao salvar um evento. Na função de carregamento, computar se a data atual corresponde à regra de recorrência (por exemplo, todas as segundas-feiras) e exibir o evento em conformidade. Armazene as regras de recorrência em uma chave de armazenamento local separada para evitar duplicações.

Vista Semanal e Calendário Mini

Alterna entre as vistas do mês e da semana. Uma vista semanal mostra apenas os dias da semana atual com mais espaço horizontal. Um pequeno calendário de mini-visão mensal ajuda os usuários a saltar para qualquer data rapidamente.

Tornar o calendário responsivo e acessível

Teste o calendário em vários tamanhos de tela. Use ] consultas para empilhar células do dia verticalmente em telas muito pequenas ou para reduzir o preenchimento. Certifique-se de que todos os elementos interativos são acessíveis ao teclado: anexe eventos para Enter e Escape. Use atributos em botões e regiões ao vivo para leitores de tela para anunciar mudanças de mês e adições de eventos.

Dicas de desempenho e gerenciamento de dados

  • Escritas de Armazenamento em Bloqueio: Em vez de ler/escrever Armazenamento Local para cada operação de evento, cache os eventos do mês inteiro em um objeto JavaScript e flush muda periodicamente.
  • Limite o Tamanho do Evento: Mantenha os objetos de eventos pequenos. Evite armazenar grandes strings ou dados binários.
  • Fallback for Storage Limits: Armazenamento local é normalmente fechado em 5-10 MB. Avise os usuários quando o armazenamento está quase cheio.
  • Use indexedDB para grandes conjuntos de dados: Se seu calendário irá conter milhares de eventos, considere IndexedDB para melhor desempenho e capacidade de consulta.

Conclusão

Criar uma aplicação de calendário personalizada com o JavaScript e o Armazenamento Local é um projecto gratificante que aguça as suas capacidades de front-end. Você aprende a manipular o DOM, trabalhar com datas, gerir o estado sem servidor e lidar com as interacções do utilizador. A base de código pode ser estendida com a sincronização do servidor, o backup da nuvem ou a integração com calendários externos através da API do Google Calendar. Comece com a grelha básica, adicione persistência e depois a camada em funcionalidades como arrastar- e- soltar e eventos recorrentes. O resultado é um calendário personalizado que se comporta exactamente como você precisa.

Para leitura posterior, explore a documentação Storage API e Drag and Drop API] no MDN. Happy coding!