最新文章
FullCalendar 日歷應用
我將創(chuàng)建一個使用FullCalendar庫的現(xiàn)代化日歷應用,包含事件管理、主題切換等功能。 使用FullCalendar v5展示日歷視圖 添加事件管理功能(增刪改查) 實現(xiàn)亮色/暗色主題切換 設計響應式布局適配不同設備 添加直觀的操作界面 下面是完整的實現(xiàn)代碼: html 日歷視圖 月、周、日視圖切換 導航按鈕(上個月、今天、下個月) 事件點擊可刪除 事件管理 添加事件(包含標題、描述、顏色) 事件列表展示 事件刪除功能 主題切換 亮色/暗色主題切換 自動適配日歷主題 響應式設計 適配不同屏幕尺寸 移動設備優(yōu)化 UI 設計 現(xiàn)代化卡片式設計 漸變色標題 直觀的圖標和按鈕 在左側(cè)表單輸入事件信息 選擇事件顏色 點擊"添加事件"按鈕 事件將出現(xiàn)在日歷和右側(cè)列表中 點擊事件可刪除 使用頂部按鈕切換月份 使用右上角按鈕切換主題 這個應用完全使用HTML、CSS和JavaScript實現(xiàn),不需要任何后端支持,可以直接在瀏覽器中運行。設計思路
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FullCalendar 日歷應用</title> <!-- FullCalendar 核心樣式 --> <link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.css" rel="stylesheet"> <!-- Google Fonts --> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Material+Icons&display=swap" rel="stylesheet"> <style> :root { --primary-color: #4361ee; --secondary-color: #3f37c9; --accent-color: #4895ef; --success-color: #4cc9f0; --text-color: #333; --bg-color: #f8f9fa; --card-bg: #ffffff; --border-color: #e0e0e0; --shadow: 0 4px 12px rgba(0,0,0,0.08); --event-color: #4361ee; } .dark-theme { --primary-color: #4895ef; --secondary-color: #4361ee; --accent-color: #3f37c9; --success-color: #4cc9f0; --text-color: #e0e0e0; --bg-color: #121212; --card-bg: #1e1e1e; --border-color: #333; --shadow: 0 4px 12px rgba(0,0,0,0.3); --event-color: #4895ef; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Roboto', sans-serif; background-color: var(--bg-color); color: var(--text-color); transition: all 0.3s ease; } .container { max-width: 1400px; margin: 0 auto; padding: 20px; } header { display: flex; justify-content: space-between; align-items: center; padding: 20px 0; margin-bottom: 30px; border-bottom: 1px solid var(--border-color); } .logo { display: flex; align-items: center; gap: 15px; } .logo h1 { font-size: 28px; font-weight: 700; background: linear-gradient(45deg, var(--primary-color), var(--success-color)); -webkit-background-clip: text; background-clip: text; color: transparent; } .logo-icon { font-size: 32px; color: var(--primary-color); } .controls { display: flex; gap: 15px; align-items: center; } .btn { padding: 10px 20px; border-radius: 8px; border: none; font-weight: 500; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; gap: 8px; } .btn-primary { background: var(--primary-color); color: white; } .btn-primary:hover { background: var(--secondary-color); transform: translateY(-2px); } .btn-outline { background: transparent; border: 1px solid var(--primary-color); color: var(--primary-color); } .btn-outline:hover { background: rgba(67, 97, 238, 0.1); } .theme-toggle { width: 50px; height: 26px; background: var(--border-color); border-radius: 13px; position: relative; cursor: pointer; } .theme-toggle::before { content: ''; position: absolute; width: 20px; height: 20px; border-radius: 50%; background: white; top: 3px; left: 3px; transition: all 0.3s ease; } .dark-theme .theme-toggle::before { left: 27px; background: #333; } .main-content { display: grid; grid-template-columns: 1fr 350px; gap: 30px; } @media (max-width: 992px) { .main-content { grid-template-columns: 1fr; } } .calendar-container { background: var(--card-bg); border-radius: 12px; padding: 20px; box-shadow: var(--shadow); height: 700px; } #calendar { height: 100%; } .events-panel { background: var(--card-bg); border-radius: 12px; padding: 25px; box-shadow: var(--shadow); } .panel-title { font-size: 20px; margin-bottom: 25px; padding-bottom: 15px; border-bottom: 1px solid var(--border-color); display: flex; align-items: center; gap: 10px; } .event-form { display: flex; flex-direction: column; gap: 20px; margin-bottom: 30px; padding-bottom: 25px; border-bottom: 1px solid var(--border-color); } .form-group { display: flex; flex-direction: column; gap: 8px; } .form-group label { font-weight: 500; font-size: 15px; } .form-group input, .form-group textarea { padding: 12px; border-radius: 8px; border: 1px solid var(--border-color); background: var(--bg-color); color: var(--text-color); font-family: inherit; } .form-group textarea { min-height: 100px; resize: vertical; } .events-list { display: flex; flex-direction: column; gap: 15px; max-height: 350px; overflow-y: auto; padding-right: 10px; } .event-item { background: var(--bg-color); padding: 15px; border-radius: 8px; border-left: 4px solid var(--primary-color); transition: all 0.2s ease; cursor: pointer; } .event-item:hover { transform: translateX(5px); } .event-title { font-weight: 500; margin-bottom: 5px; display: flex; justify-content: space-between; } .event-time { font-size: 13px; color: var(--accent-color); margin-bottom: 8px; } .event-description { font-size: 14px; color: var(--text-color); opacity: 0.9; } .color-picker { display: flex; gap: 10px; flex-wrap: wrap; } .color-option { width: 30px; height: 30px; border-radius: 50%; cursor: pointer; border: 2px solid transparent; transition: all 0.2s ease; } .color-option.active { border-color: white; box-shadow: 0 0 0 2px var(--text-color); } .no-events { text-align: center; padding: 20px; color: #888; font-style: italic; } footer { text-align: center; padding: 30px 0; margin-top: 50px; color: #777; font-size: 14px; border-top: 1px solid var(--border-color); } @media (max-width: 768px) { header { flex-direction: column; gap: 20px; } .logo h1 { font-size: 24px; } .calendar-container { height: 500px; } } </style> </head> <body> <div> <header> <div> <span class="logo-icon material-icons">calendar_today</span> <h1>FullCalendar 應用</h1> </div> <div> <button id="prev-btn" class="btn btn-outline"> <span>chevron_left</span> 上個月 </button> <button id="today-btn" class="btn btn-outline"> <span>today</span> 今天 </button> <button id="next-btn" class="btn btn-outline"> 下個月 <span>chevron_right</span> </button> <div id="theme-toggle"></div> </div> </header> <div> <div> <div id="calendar"></div> </div> <div> <h2> <span>event</span> 事件管理 </h2> <div> <div> <label for="event-title">事件標題</label> <input type="text" id="event-title" placeholder="輸入事件標題"> </div> <div> <label for="event-description">事件描述</label> <textarea id="event-description" placeholder="輸入事件描述"></textarea> </div> <div> <label>事件顏色</label> <div> <div class="color-option active" style="background-color: #4361ee;" data-color="#4361ee"></div> <div style="background-color: #4cc9f0;" data-color="#4cc9f0"></div> <div style="background-color: #7209b7;" data-color="#7209b7"></div> <div style="background-color: #f72585;" data-color="#f72585"></div> <div style="background-color: #2ec4b6;" data-color="#2ec4b6"></div> <div style="background-color: #ff9e00;" data-color="#ff9e00"></div> </div> </div> <button id="add-event" class="btn btn-primary"> <span>add</span> 添加事件 </button> </div> <h3> <span>list</span> 事件列表 </h3> <div id="events-container"> <div>暫無事件,請?zhí)砑邮录?lt;/div> </div> </div> </div> <footer> <p>? 2023 FullCalendar 日歷應用 | 使用 FullCalendar v5 構(gòu)建</p> </footer> </div> <!-- FullCalendar 核心庫 --> <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.js"></script> <!-- 中文語言包 --> <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/locales/zh-cn.min.js"></script> <script> // 初始化變量 let events = []; let selectedColor = '#4361ee'; // DOM 元素 const calendarEl = document.getElementById('calendar'); const eventsContainer = document.getElementById('events-container'); const themeToggle = document.getElementById('theme-toggle'); const prevBtn = document.getElementById('prev-btn'); const nextBtn = document.getElementById('next-btn'); const todayBtn = document.getElementById('today-btn'); const addEventBtn = document.getElementById('add-event'); const eventTitle = document.getElementById('event-title'); const eventDescription = document.getElementById('event-description'); const colorOptions = document.querySelectorAll('.color-option'); // 初始化日歷 const calendar = new FullCalendar.Calendar(calendarEl, { initialView: 'dayGridMonth', locale: 'zh-cn', headerToolbar: { left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay' }, buttonText: { today: '今天', month: '月', week: '周', day: '日' }, events: events, eventClick: function(info) { // 點擊事件時刪除 if (confirm(`確定要刪除 "${info.event.title}" 事件嗎?`)) { info.event.remove(); events = events.filter(e => e.id !== info.event.id); renderEvents(); } }, dateClick: function(info) { // 點擊日期時自動填充日期 eventTitle.focus(); alert(`您選擇了日期: ${info.dateStr}`); }, eventDisplay: 'block', eventColor: selectedColor }); calendar.render(); // 主題切換 themeToggle.addEventListener('click', function() { document.body.classList.toggle('dark-theme'); // 更新日歷主題 const theme = document.body.classList.contains('dark-theme') ? 'dark' : 'light'; calendar.setOption('themeSystem', theme); }); // 導航按鈕 prevBtn.addEventListener('click', function() { calendar.prev(); }); nextBtn.addEventListener('click', function() { calendar.next(); }); todayBtn.addEventListener('click', function() { calendar.today(); }); // 顏色選擇 colorOptions.forEach(option => { option.addEventListener('click', function() { colorOptions.forEach(opt => opt.classList.remove('active')); this.classList.add('active'); selectedColor = this.dataset.color; }); }); // 添加事件 addEventBtn.addEventListener('click', function() { const title = eventTitle.value.trim(); const description = eventDescription.value.trim(); if (!title) { alert('請輸入事件標題'); return; } const newEvent = { id: Date.now().toString(), title: title, description: description, start: new Date(), color: selectedColor }; events.push(newEvent); calendar.addEvent(newEvent); renderEvents(); // 重置表單 eventTitle.value = ''; eventDescription.value = ''; }); // 渲染事件列表 function renderEvents() { if (events.length === 0) { eventsContainer.innerHTML = '<div>暫無事件,請?zhí)砑邮录?lt;/div>'; return; } eventsContainer.innerHTML = ''; events.forEach(event => { const eventDate = new Date(event.start); const eventEl = document.createElement('div'); eventEl.className = 'event-item'; eventEl.style.borderLeftColor = event.color; eventEl.innerHTML = ` <div> <span>${event.title}</span> <span style="color:${event.color}">circle</span> </div> <div>${eventDate.toLocaleString()}</div> <div>${event.description || '無描述'}</div> `; eventEl.addEventListener('click', function() { if (confirm(`確定要刪除 "${event.title}" 事件嗎?`)) { // 從日歷和列表中刪除 calendar.getEventById(event.id).remove(); events = events.filter(e => e.id !== event.id); renderEvents(); } }); eventsContainer.appendChild(eventEl); }); } // 初始渲染 renderEvents(); </script> </body> </html>
功能說明
使用方法