尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

原生 JS 实现自定义单选日历组件(无 UI 库、纯手写、禁用过去日期)

原生 JS 实现自定义单选日历组件(无 UI 库、纯手写、禁用过去日期)
📅 发布时间:2026/7/12 10:23:27

前言
在后台管理、表单页面开发中,日期选择是高频需求。项目中经常会遇到两种场景:一是不想引入Element UI、Ant Design等重型 UI 框架,减少打包体积;二是产品要求日历样式高度自定义,原生input[type=“date”]样式无法修改,无法满足设计稿。
本文基于原生 JavaScript + jQuery(仅引入基础库,DOM 简化操作) 从零手写一套独立悬浮单选日历,具备以下特性:
完全自定义样式,弹窗定位跟随输入框;
支持上 / 下一月、上 / 下一年快速切换;
自动区分上月 / 当月 / 下月日期,灰色置灰非当月天数;
核心业务逻辑:所有过去日期禁用不可点击,仅可选择今日及未来日期;
「今天」快捷按钮,一键选中当前日期并关闭弹窗;
点击空白区域自动关闭日历,防止弹窗滞留;
日期输出统一YYYY-MM-DD标准格式,直接适配后端接口;
低耦合结构,单文件开箱即用,可快速复用至任意表单。
全文附带完整可运行源码、逐行逻辑拆解、关键 API 说明、踩坑点总结,新手也能完全看懂,可直接落地项目。
一、整体结构分层设计
整个日历组件分为三层:输入框层、日历弹窗容器、日历内部渲染模块,结构完全解耦:
输入框 .date_input:只读文本框,内置日历图标,点击唤起弹窗;
弹窗容器 .calendar_wrap:fixed 悬浮定位,默认隐藏,点击输入框计算坐标展示;
日历内部模块
头部导航:年份 / 月份切换按钮 + 当前年月标题;
星期头部:周日到周六固定表头;
日期格子容器:动态渲染 42 格日期(固定 6 行 ×7 列,保证布局稳定);
底部快捷按钮:回到今日。
CSS 设计规范说明
输入框内置 svg 日历图标,无需引入图片资源,减少 HTTP 请求;
弹窗使用fixed定位,通过getBoundingClientRect实时获取输入框坐标,永远紧贴输入框下方;
样式分层隔离:日历所有样式统一包裹在.calendar_wrap下,不会污染页面其他元素;
状态类区分:
.other:上月 / 下月灰色无效日期;
.disabled:已过期、不可点击日期;
.active:当前选中日期高亮底色;
交互优化:hover 高亮有效日期、弹窗阴影分层,提升视觉体验。
二、完整可运行源码
html
预览

原生自定义单选日历组件
« ‹
2026年 Jun
› »
Su
Mo
Tu
We
Th
Fr
Sa
今天
<script> // 获取全局DOM元素,缓存节点减少重复DOM查询,提升性能 const inp = document.querySelector('.date_input'); const calWrap = document.getElementById('calendar'); const dayBox = document.getElementById('dayBox'); const calTitle = document.getElementById('calTitle'); const todayBtn = document.getElementById('todayBtn'); // 控制日历当前展示年月的基准日期 let nowDate = new Date(); // 月份英文简写映射,用于顶部标题渲染 const monthArr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; // ===================== 1. 输入框点击唤起日历 ===================== inp.onclick = function (e) { // 阻止冒泡,避免触发body关闭弹窗事件 e.stopPropagation(); // getBoundingClientRect:获取输入框相对视口的坐标 const rect = inp.getBoundingClientRect(); // 弹窗定位:左对齐输入框,输入框下方8px展示 calWrap.style.left = rect.left + 'px'; calWrap.style.top = rect.bottom + 8 + 'px'; calWrap.style.display = 'block'; // 每次打开重新渲染当月日期(防止跨天打开日历日期不刷新) renderCal(); } // 点击页面空白处关闭日历弹窗 document.body.onclick = () => calWrap.style.display = 'none'; // 点击日历内部阻止冒泡,不会关闭弹窗 calWrap.onclick = e => e.stopPropagation(); // ===================== 2. 核心渲染函数 renderCal ===================== function renderCal() { // 获取当前系统今日,清空时分秒用于日期对比(仅比较年月日) const today = new Date(); today.setHours(0, 0, 0, 0); // 获取当前展示年份、月份 const y = nowDate.getFullYear(); const m = nowDate.getMonth(); // 渲染顶部年月标题 calTitle.innerText = `${y}年 ${monthArr[m]}`; // 清空上次渲染的日期格子 dayBox.innerHTML = ''; // 关键日期计算API说明 const firstDay = new Date(y, m, 1).getDay(); // 当月1号是星期几(0=周日~6=周六) const curMonthDays = new Date(y, m + 1, 0).getDate(); // 当前月份总天数 const lastMonthDays = new Date(y, m, 0).getDate(); // 上个月总天数 // 第一部分:渲染上月末尾剩余日期,全部置灰 .other for (let i = 0; i < firstDay; i++) { let d = lastMonthDays - firstDay + i + 1; dayBox.innerHTML += `<div class="day-item other">${d}</div>`; } // 第二部分:渲染当月完整日期(核心逻辑:判断过期禁用、选中高亮) for (let i = 1; i <= curMonthDays; i++) { const currentDate = new Date(y, m, i); currentDate.setHours(0, 0, 0, 0); let cls = ''; // 当前选中日期添加active高亮 if (i === nowDate.getDate()) cls = 'active'; // 日期小于今日,添加disabled禁用类,不可点击 if (currentDate < today) { cls += ' disabled'; } // padStart补零,统一输出 YYYY-MM-DD 标准日期格式 const formatMonth = String(m + 1).padStart(2, '0'); const formatDay = String(i).padStart(2, 0); dayBox.innerHTML += `<div class="day-item ${cls}">

相关新闻

  • Cesium 热力图教程
  • 3分钟搞定Godot游戏资源提取:终极PCK解包指南
  • 古法黄金饰品多品牌实测:工艺质感与保值性对比评测 - 招财兔数字员工

最新新闻

  • 高精度ADC系统设计与优化:基于ADS131M02与PIC18F55K42
  • 微程序控制器设计实战:24位微指令实现5条机器指令(附完整微代码表)
  • ThinkPad风扇噪音终结者:TPFanCtrl2智能控温完全指南
  • Unity XR Interaction Toolkit实战:5分钟集成Pico VR手柄移动、抓取与瞬移
  • NS模拟器管理终极指南:NsEmuTools深度解析与实战应用
  • DHCP 主机名冲突排查:2个客户端同名导致 dnsmasq 记录覆盖分析

日新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号