登录
首页 >  文章 >  前端

自定义月份年份选择器实现方法

时间:2026-01-19 11:01:03 162浏览 收藏

知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个文章开发实战,手把手教大家学习《如何自定义月份年份选择器实现方法》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!

如何创建一个自定义的月份与年份选择器

本文介绍如何用原生 JavaScript 构建轻量、可定制的月年选择器,重点解决初始化时年份显示错误(如默认显示 2024 而非当前年 2023)及当前年被误禁用的问题,并提供完整可运行代码与关键逻辑解析。

在开发表单或日期筛选功能时,标准 <input type="date"> 无法满足仅选择“年+月”的需求,而引入大型 UI 库又显得过度。此时,一个简洁、可控的自定义月年选择器(Month-Year Picker)是理想方案。本文将带你从零实现一个纯原生、无依赖的解决方案,并精准修复两个常见初始化缺陷:

  • ✅ 页面加载时,默认应显示「当前年 + 当前月」(如 2023 年 7 月),而非错误地显示 2024 年;
  • ✅ 当用户选择当前月份(如 7 月)时,当前年(2023)必须始终可用,不可被意外禁用。

? 核心问题根源:执行顺序导致状态错位

原始代码中,updateYearOptions() 在 updateMonthOptions() 之前调用:

updateYearOptions(); // ❌ 此时 month &lt;select&gt; 值仍为默认 1(January)
updateMonthOptions();

由于 <select id="month"> 初始值为 1(January),而当前月份是 7(July),条件 selectedMonth < currentMonth 成立 → 错误禁用 2023 年选项,且 selectedYear 初始化为 2023,但该选项已被禁用,触发回退逻辑 yearToSelect = year + 1,最终选中 2024。

解法极其简洁:调整初始化顺序,确保月份先设为正确值,再生成年份选项。

✅ 修复后的完整实现

<!DOCTYPE html>
<html>
<head>
  <style>
    body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }
    #datepicker { width: 400px; padding: 10px; border: 1px solid #ccc; }
  </style>
</head>
<body>
  <div id="datepicker">
    <label for="month">Month:</label>
    &lt;select id=&quot;month&quot; onchange=&quot;updateYearOptions()&quot;&gt;
      <option value="1">January</option>
      <option value="2">February</option>
      <option value="3">March</option>
      <option value="4">April</option>
      <option value="5">May</option>
      <option value="6">June</option>
      <option value="7">July</option>
      <option value="8">August</option>
      <option value="9">September</option>
      <option value="10">October</option>
      <option value="11">November</option>
      <option value="12">December</option>
    &lt;/select&gt;

    <label for="year">Year:</label>
    &lt;select id=&quot;year&quot; onchange=&quot;updateSelectedYear()&quot;&gt;&lt;/select&gt;
    &lt;input type=&quot;hidden&quot; id=&quot;selectedYear&quot; name=&quot;selectedYear&quot;&gt;
  </div>

  <script>
    let selectedYear = new Date().getFullYear();

    function updateYearOptions() {
      const now = new Date();
      const currentYear = now.getFullYear();
      const currentMonth = now.getMonth() + 1; // 1–12
      const selectedMonth = parseInt(document.getElementById('month').value);

      const yearSelect = document.getElementById('year');
      const maxYear = currentYear + 20;
      yearSelect.innerHTML = '';

      let yearToSelect = selectedYear;

      for (let year = currentYear; year <= maxYear; year++) {
        const option = document.createElement('option');
        option.value = year;
        option.textContent = year;

        // 仅当选择的月份 < 当前月份时,禁用当前年(防止选“2023年5月”这种已过期组合)
        if (year === currentYear && selectedMonth < currentMonth) {
          option.disabled = true;
        }

        // 若预设的 selectedYear 被禁用,则自动 fallback 到下一个可用年份
        if (year === selectedYear && option.disabled) {
          yearToSelect = year + 1;
        }

        yearSelect.appendChild(option);
      }

      yearSelect.value = yearToSelect;
      selectedYear = yearToSelect;
      document.getElementById('selectedYear').value = yearToSelect;
    }

    function updateMonthOptions() {
      const monthSelect = document.getElementById('month');
      const currentMonth = new Date().getMonth() + 1;
      monthSelect.value = currentMonth; // ✅ 关键:先设好月份,再生成年份
    }

    // ✅ 初始化顺序修正:先设月,再生成年选项
    updateMonthOptions();
    updateYearOptions();

    function updateSelectedYear() {
      selectedYear = parseInt(document.getElementById('year').value);
      document.getElementById('selectedYear').value = selectedYear;
    }
  </script>
</body>
</html>

⚠️ 注意事项与增强建议

  • 语义化与可访问性:为 <select> 添加 aria-label 或关联
  • 动态范围扩展:如需支持历史年份(如出生年份),可将循环起始年改为 currentYear - 100,并添加 minYear 配置;
  • 响应式交互:可增加 onfocus 事件,在点击年份下拉时自动触发 updateYearOptions(),确保每次展开都基于最新月份;
  • 防重复提交:隐藏字段 #selectedYear 仅作数据传递,实际提交时建议组合 month 和 year 值(如 "2023-07")以符合后端 API 规范。

此方案零依赖、体积小、逻辑清晰,既满足基础业务需求,又为后续定制(如国际化、主题切换、动画过渡)预留了充足空间。掌握其核心——状态初始化顺序 + 条件禁用策略——即可快速复用于各类时间维度筛选场景。

今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

前往漫画官网入口并下载 ➜
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>