min/max 属性仅限制 UI 日历选项,无法阻止手动输入等非法操作,需配合 JavaScript 校验;格式必须严格为 YYYY-MM-DD,动态设置推荐使用 toISOString().slice(0,10),设置后需用 setAttribute 或 dispatchEvent 触发重绘,且 change 事件中须二次校验并调用 setCustomValidity。

直接用 min 和 max 属性就能限制 UI 范围,但必须配合 JavaScript 校验才能真正拦住非法输入——浏览器只灰掉日历选项,不阻止手动敲、粘贴或脚本赋值。
min/max 的格式必须严格为 YYYY-MM-DD
任何偏差都会导致属性静默失效:比如 "2026/10/20"、"2026-10-20T00:00"、"2026-10-2"(缺零)全都不认。动态设置时别手拼字符串,容易漏补零:
- ✅ 推荐:
new Date().toISOString().slice(0, 10)—— 稳定输出"2026-10-20" - ❌ 避免:
date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate()—— 月份/日期没padStart(2, '0')就会变成"2026-10-2",无效 - ❌ 避免:
toLocaleDateString('sv-SE')—— 地区不同结果不一,不可控
动态设置后 UI 不更新?用 setAttribute 或触发重绘
Safari 和部分旧版 Chrome 中,直接写 input.min = "2026-10-20" 可能不刷新日历界面,用户仍能点选超限日期:
- ✅ 可靠做法:
input.setAttribute('min', '2026-10-20')—— 强制 DOM 属性变更,触发重绘 - ✅ 备选方案:
input.min = '2026-10-20'; input.dispatchEvent(new Event('input', { bubbles: true })) - ⚠️ 注意:如果
input.value已超出新设的max,浏览器不会自动清空,得手动判断:if (input.value && input.value > input.max) input.value = ''
必须监听 change 做二次校验
min/max 完全不限制键盘输入、粘贴、DevTools 修改等行为。仅靠它们提交表单时照样过,后端收到的可能是 "1999-01-01":
立即学习“前端免费学习笔记(深入)”;
- ✅ 监听
change事件(不是input,避免频繁触发) - ✅ 检查
input.valueAsDate是否存在,再和new Date(input.min)比大小 - ✅ 非法时立刻清空:
input.value = '',并调用input.setCustomValidity('日期不在允许范围内')+input.reportValidity() - ⚠️ 移动端 Safari 的
change触发不稳定,建议额外监听blur做兜底
最容易被忽略的是:前端所有限制都基于本地日历日,而后端可能按 UTC 存储或解析;用户在不同时区下看到的“今天”可能对应服务端的昨天或明天——所以服务端必须独立解析传入的 YYYY-MM-DD 字符串,并按业务规则重新映射到目标时区再做范围判断。



















