You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态日历年份切换时月份下拉框默认值异常问题求助

动态日历月份选择异常问题排查与修复

我正在开发一款可从谷歌日历获取事件的动态日历,目前已实现核心功能:

  • 选择当前年份(如2024年)时,月份下拉框仅展示当前及之后月份
  • 选择未来年份时展示全部月份,该逻辑运行正常

但存在关键问题:当查看未来年份中早于当前月份的月份(如2025年3月)时,切换回当前年份(2024年),月份下拉框应默认选中当前月份(7月)并更新日历渲染相关变量,但实际会选中下拉框中不存在的选项。调试数小时仍未解决,附上相关代码求助:

function populateMonths() {
    const selectMonth = document.getElementById('selectMonth');
    const currentYear = new Date().getFullYear();
    const currentMonth = new Date().getMonth();
    const months = [
        'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 
        'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'
    ];

    selectMonth.innerHTML = ''; // Clear existing options

    let startMonth = 0;
    if (selectedYear === currentYear) {
        startMonth = currentMonth; // Show from current month onwards
    }

    console.log(`currentYear: ${currentYear}`);
    console.log(`currentMonth: ${currentMonth}`);
    console.log(`selectedYear: ${selectedYear}`);
    console.log(`selectedMonth: ${selectedMonth}`);
    console.log(`startMonth: ${startMonth}`);

    months.slice(startMonth).forEach((month, index) => {
        const monthIndex = startMonth + index;
        const option = document.createElement('option');
        option.value = monthIndex; // Adjust value to reflect actual month index
        option.textContent = months[monthIndex];
        selectMonth.appendChild(option);
    });

    selectMonth.selectedIndex = selectedMonth - startMonth;

    console.log(`Final selectedIndex: ${selectMonth.selectedIndex}`);
}



function populateYears() {
    const selectYear = document.getElementById('selectYear');
    const currentYear = new Date().getFullYear();
    const yearsToShow = 3; // Number of years to show, starting from the current year

    selectYear.innerHTML = ''; // Clear existing options

    for (let i = 0; i < yearsToShow; i++) {
        const year = currentYear + i;
        const option = document.createElement('option');
        option.value = year;
        option.textContent = year;
        selectYear.appendChild(option);
    }

    selectYear.value = selectedYear;
}

function changeMonth() {
    selectedMonth = parseInt(document.getElementById('selectMonth').value);
    renderCalendar(selectedYear, selectedMonth);
}

function changeYear() {
    selectedYear = parseInt(document.getElementById('selectYear').value);
    populateMonths();
    renderCalendar(selectedYear, selectedMonth);
}

function renderCalendar(year, month) {
    const calendar = document.getElementById('calendar');
    calendar.innerHTML = '';

    const firstDayOfMonth = new Date(year, month, 1);
    const lastDayOfMonth = new Date(year, month + 1, 0);
    const daysInMonth = lastDayOfMonth.getDate();

    const startingDay = firstDayOfMonth.getDay(); // 0 (Sunday) to 6 (Saturday)
    const daysOfWeek = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'];

    // Create header row for days of the week
    for (let day = 0; day < 7; day++) {
        const cell = document.createElement('div');
        cell.classList.add('cell', 'header-cell');
        cell.textContent = daysOfWeek[day];
        calendar.appendChild(cell);
    }

    // Create blank cells for the days before the first day of the month
    for (let i = 0; i < startingDay; i++) {
        const cell = document.createElement('div');
        cell.classList.add('cell', 'empty-cell');
        calendar.appendChild(cell);
    }

    // Create cells for each day in the month
    for (let i = 1; i <= daysInMonth; i++) {
        const date = new Date(year, month, i);
        const dateString = formatDate(date); // Format date to 'YYYY-MM-DD'

        const cell = document.createElement('div');
        cell.classList.add('cell');
        cell.textContent = i;

        const dayEvents = events.filter(event => event.date === dateString);

        if (isFullyBooked(dateString)) {
            cell.classList.add('booked');
            cell.title = 'Totalmente reservado';
        } else if (isHalfBooked(dayEvents)) {
            cell.classList.add('half-booked');
            cell.title = 'Parcialmente reservado';
            cell.addEventListener('mouseover', () => showAvailableHoursTooltip(cell, dayEvents));
            cell.addEventListener('mouseout', hideTooltip);
        } else {
            cell.classList.add('available');
            cell.title = 'Disponível';
        }

        calendar.appendChild(cell);
    }
}

问题原因

问题出在populateMonths函数设置selectedIndex的逻辑上:当从未来年份(比如2025年3月,此时selectedMonth为2)切换回当前年份(2024年,startMonth为6),计算selectedMonth - startMonth得到2-6=-4,这是一个无效的下拉框索引,导致选中不存在的选项。

修复方案

在populateMonths函数中添加判断,确保selectedMonth始终处于当前年份的可选月份范围内。如果不在范围内,将其重置为startMonth(当前年份的当前月份),再计算选中索引。

修复后的populateMonths函数:

function populateMonths() {
    const selectMonth = document.getElementById('selectMonth');
    const currentYear = new Date().getFullYear();
    const currentMonth = new Date().getMonth();
    const months = [
        'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 
        'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'
    ];

    selectMonth.innerHTML = ''; // Clear existing options

    let startMonth = 0;
    if (selectedYear === currentYear) {
        startMonth = currentMonth; // Show from current month onwards
    }

    // 关键修复:确保选中的月份在可选范围内,否则重置为当前月份
    if (selectedMonth < startMonth) {
        selectedMonth = startMonth;
    }

    console.log(`currentYear: ${currentYear}`);
    console.log(`currentMonth: ${currentMonth}`);
    console.log(`selectedYear: ${selectedYear}`);
    console.log(`selectedMonth: ${selectedMonth}`);
    console.log(`startMonth: ${startMonth}`);

    months.slice(startMonth).forEach((month, index) => {
        const monthIndex = startMonth + index;
        const option = document.createElement('option');
        option.value = monthIndex; // Adjust value to reflect actual month index
        option.textContent = months[monthIndex];
        selectMonth.appendChild(option);
    });

    selectMonth.selectedIndex = selectedMonth - startMonth;

    console.log(`Final selectedIndex: ${selectMonth.selectedIndex}`);
}

额外说明

  • 添加的判断逻辑保证selectedMonth始终是当前年份可选的月份,避免计算出无效索引
  • 重置selectedMonth后,后续renderCalendar调用也会使用正确的月份,确保日历渲染正常

内容的提问来源于stack exchange,提问作者Kripthonite

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 00:22:33