如何实现选择指定年月后展示对应日历,其余内容仅可读不可选?
嘿,这个需求很清晰,我给你整了一套完整的实现方案,包含HTML、CSS和JavaScript,直接就能复用:
实现思路
核心逻辑就是:监听月份和年份选择框的变化,当选中1月 + 2018年时,渲染可交互的完整日历;其他情况渲染只读状态的日历(日期不可点击、样式灰化)。
HTML 结构
先搭好基础的选择器和日历容器:
<div class="calendar-controls"> <select id="month-select"> <option value="1">1月</option> <option value="2">2月</option> <option value="3">3月</option> <option value="4">4月</option> <option value="5">5月</option> <option value="6">6月</option> <option value="7">7月</option> <option value="8">8月</option> <option value="9">9月</option> <option value="10">10月</option> <option value="11">11月</option> <option value="12">12月</option> </select> <select id="year-select"> <option value="2017">2017年</option> <option value="2018" selected>2018年</option> <option value="2019">2019年</option> <option value="2020">2020年</option> </select> </div> <div class="calendar-container" id="calendar-container"> <div class="calendar-header"> <div>日</div> <div>一</div> <div>二</div> <div>三</div> <div>四</div> <div>五</div> <div>六</div> </div> <div class="calendar-days" id="calendar-days"></div> </div>
CSS 样式
给日历加上基础样式,区分可交互和只读状态:
.calendar-controls { margin-bottom: 1rem; } .calendar-container { max-width: 400px; font-family: Arial, sans-serif; } .calendar-header { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; margin-bottom: 5px; font-weight: bold; text-align: center; } .calendar-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; } .calendar-day { padding: 10px; text-align: center; border: 1px solid #eee; cursor: pointer; transition: background-color 0.2s; } .calendar-day:hover { background-color: #f0f0f0; } /* 只读状态样式 */ .readonly-calendar .calendar-day { cursor: not-allowed; color: #999; } .readonly-calendar .calendar-day:hover { background-color: transparent; } /* 非当月日期样式(可选) */ .calendar-day.other-month { color: #ccc; }
JavaScript 逻辑
实现日历生成和状态控制的核心代码:
const monthSelect = document.getElementById('month-select'); const yearSelect = document.getElementById('year-select'); const calendarDays = document.getElementById('calendar-days'); const calendarContainer = document.getElementById('calendar-container'); // 初始化日历 renderCalendar(); // 监听选择器变化 monthSelect.addEventListener('change', renderCalendar); yearSelect.addEventListener('change', renderCalendar); function renderCalendar() { const selectedMonth = monthSelect.value; // 1-12 const selectedYear = yearSelect.value; const isInteractive = selectedMonth === '1' && selectedYear === '2018'; // 设置日历状态 if (isInteractive) { calendarContainer.classList.remove('readonly-calendar'); } else { calendarContainer.classList.add('readonly-calendar'); } // 清空之前的日期 calendarDays.innerHTML = ''; // 处理月份转换(JS Date 月份是0-11) const jsMonth = parseInt(selectedMonth) - 1; const firstDayOfMonth = new Date(selectedYear, jsMonth, 1); const lastDayOfMonth = new Date(selectedYear, jsMonth + 1, 0); const daysInMonth = lastDayOfMonth.getDate(); const startWeekDay = firstDayOfMonth.getDay(); // 0=周日,6=周六 // 填充当月之前的空白日期 for (let i = 0; i < startWeekDay; i++) { const emptyDay = document.createElement('div'); emptyDay.classList.add('calendar-day', 'other-month'); calendarDays.appendChild(emptyDay); } // 填充当月日期 for (let day = 1; day <= daysInMonth; day++) { const dayElement = document.createElement('div'); dayElement.classList.add('calendar-day'); dayElement.textContent = day; // 只有可交互状态下添加点击事件 if (isInteractive) { dayElement.addEventListener('click', () => { alert(`你选中了 ${selectedYear}年${selectedMonth}月${day}日`); // 这里可以替换成你的业务逻辑 }); } calendarDays.appendChild(dayElement); } // 填充当月之后的空白日期 const totalCells = startWeekDay + daysInMonth; const remainingCells = 42 - totalCells; // 6行*7列=42个格子 for (let i = 0; i < remainingCells; i++) { const emptyDay = document.createElement('div'); emptyDay.classList.add('calendar-day', 'other-month'); calendarDays.appendChild(emptyDay); } }
关键说明
- 当选中1月2018时,日历会移除
readonly-calendar类,日期可点击并触发自定义逻辑;其他情况添加该类,日期灰化且不可点击。 - 日历自动处理了当月前后的空白日期,保证布局整齐(6行固定高度)。
- 你可以根据需求调整年份范围、日历样式,或者修改点击事件里的业务逻辑。
内容的提问来源于stack exchange,提问作者Parth Makwana
相关产品推荐
相关产品推荐

