# JavaScript如何實現年歷效果
在現代Web開發中,日歷組件是常見的交互元素。本文將詳細介紹如何使用純JavaScript實現一個動態年歷效果,涵蓋核心邏輯、日期計算和DOM操作。
## 一、基礎HTML結構
首先創建簡單的HTML骨架,包含日歷容器和導航按鈕:
```html
<div class="calendar-container">
<div class="calendar-header">
<button id="prev-year">?</button>
<h2 id="current-year">2023</h2>
<button id="next-year">?</button>
</div>
<div id="months-container" class="months-grid"></div>
</div>
添加基礎樣式確保日歷的可視化效果:
.months-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.month-container {
border: 1px solid #ddd;
padding: 10px;
}
.month-title {
text-align: center;
margin-bottom: 10px;
}
.days-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
}
.day-header, .day-cell {
text-align: center;
padding: 5px;
}
.day-header {
font-weight: bold;
background: #f0f0f0;
}
let currentYear = new Date().getFullYear();
const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
function generateMonthData(year, month) {
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
// 計算月份開始于星期幾(0-6)
const startDay = firstDay.getDay();
return {
year,
month,
daysInMonth: lastDay.getDate(),
startDay
};
}
function renderMonth(monthData) {
const monthContainer = document.createElement('div');
monthContainer.className = 'month-container';
// 添加月份標題
const monthTitle = document.createElement('h3');
monthTitle.className = 'month-title';
monthTitle.textContent = `${monthData.month + 1}月`;
monthContainer.appendChild(monthTitle);
// 創建星期標題行
const daysHeader = document.createElement('div');
daysHeader.className = 'days-grid';
weekdays.forEach(day => {
const dayHeader = document.createElement('div');
dayHeader.className = 'day-header';
dayHeader.textContent = day;
daysHeader.appendChild(dayHeader);
});
// 創建日期格子
const daysGrid = document.createElement('div');
daysGrid.className = 'days-grid';
// 添加空白格子(月初開始的星期幾)
for (let i = 0; i < monthData.startDay; i++) {
const emptyCell = document.createElement('div');
emptyCell.className = 'day-cell';
daysGrid.appendChild(emptyCell);
}
// 添加日期數字
for (let day = 1; day <= monthData.daysInMonth; day++) {
const dayCell = document.createElement('div');
dayCell.className = 'day-cell';
dayCell.textContent = day;
// 標記當天日期
const today = new Date();
if (today.getFullYear() === monthData.year &&
today.getMonth() === monthData.month &&
today.getDate() === day) {
dayCell.classList.add('today');
}
daysGrid.appendChild(dayCell);
}
monthContainer.appendChild(daysHeader);
monthContainer.appendChild(daysGrid);
return monthContainer;
}
function renderFullYearCalendar(year) {
const monthsContainer = document.getElementById('months-container');
monthsContainer.innerHTML = '';
document.getElementById('current-year').textContent = year;
// 生成并渲染12個月份
for (let month = 0; month < 12; month++) {
const monthData = generateMonthData(year, month);
monthsContainer.appendChild(renderMonth(monthData));
}
}
document.getElementById('prev-year').addEventListener('click', () => {
currentYear--;
renderFullYearCalendar(currentYear);
});
document.getElementById('next-year').addEventListener('click', () => {
currentYear++;
renderFullYearCalendar(currentYear);
});
const festivals = {
'1-1': '元旦',
'5-1': '勞動節',
'10-1': '國慶節'
// 可擴展更多節日
};
function markFestivals(dayCell, month, day) {
const festivalKey = `${month + 1}-${day}`;
if (festivals[festivalKey]) {
const festivalMark = document.createElement('div');
festivalMark.className = 'festival-mark';
festivalMark.textContent = festivals[festivalKey];
dayCell.appendChild(festivalMark);
}
}
let selectedDate = null;
function setupDateSelection() {
document.querySelectorAll('.day-cell').forEach(cell => {
if (!cell.textContent.match(/^\d+$/)) return;
cell.addEventListener('click', () => {
// 移除之前選中的樣式
document.querySelectorAll('.selected').forEach(el => {
el.classList.remove('selected');
});
// 添加新選中樣式
cell.classList.add('selected');
selectedDate = new Date(
currentYear,
parseInt(cell.closest('.month-container')
.querySelector('.month-title').textContent) - 1,
parseInt(cell.textContent)
);
});
});
}
function checkScreenSize() {
const monthsContainer = document.getElementById('months-container');
if (window.innerWidth < 768) {
monthsContainer.style.gridTemplateColumns = 'repeat(2, 1fr)';
} else if (window.innerWidth < 480) {
monthsContainer.style.gridTemplateColumns = '1fr';
} else {
monthsContainer.style.gridTemplateColumns = 'repeat(4, 1fr)';
}
}
window.addEventListener('resize', checkScreenSize);
// 初始化日歷
document.addEventListener('DOMContentLoaded', () => {
renderFullYearCalendar(currentYear);
checkScreenSize();
});
通過本文的實現,我們完成了: 1. 動態生成任意年份的年歷 2. 正確的日期排列和星期對應 3. 基本的交互功能(年份導航) 4. 擴展功能(節日標記、日期選擇)
這個實現完全基于原生JavaScript,不依賴任何第三方庫,可以輕松集成到各種項目中。如需進一步優化,可以考慮: - 添加農歷顯示 - 實現月視圖/周視圖切換 - 增加事件提醒功能 “`
(注:實際文章約1500字,此處為保持簡潔展示了核心代碼和結構。完整版本會包含更多實現細節、注釋和原理說明。)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。