min/max 必须为严格 yyyy-mm-dd 格式字符串,如“2026-08-04”,否则浏览器静默忽略;动态生成需手动补零并用 setattribute 设置以确保 ui 刷新;服务端必须二次校验格式与逻辑范围。

min/max 必须是 YYYY-MM-DD 格式字符串
浏览器只认严格形如 "2026-08-04" 的字符串,少一个零、多一个字符、带时间或斜杠都会被静默忽略。比如 "2026-8-4"、"2026/08/04"、"2026-08-04T00:00" 全部无效——日历不灰、输入不拦、也不报错,但 input.checkValidity() 会返回 false。
动态生成时别用 toISOString().slice(0, 10):东八区用户调用 new Date().toISOString() 得到的是 UTC 时间,可能比本地日期早一天。稳妥做法是手动补零:
const d = new Date();
const minDate = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
直接赋值 input.min = minDate 在部分 Safari(iOS ≤ 15.5)中 UI 不刷新,必须用 input.setAttribute('min', minDate) 才能强制重绘。
用户仍能手动输入超限日期,这是正常行为
原生 input[type="date"] 的 min/max 只约束日历弹窗和提交校验,不拦截键盘输入。用户可以粘贴 "1999-01-01" 或直接键入任意合法格式日期,提交时 Chrome/Firefox 会阻断并提示,但 Safari(尤其旧版本)可能完全不触发校验。
- 必须监听
input或change事件做实时检查 - 若
input.value已存在且超出新设的max,浏览器不会自动清空,需显式判断:if (input.value && input.value > input.max) input.value = '' - 联动场景下(如“结束日期 ≥ 开始日期”),清空开始日期时,必须同步清空结束日期的
min,否则它会被卡死
动态设置后 UI 不更新?优先用 setAttribute
写 input.min = "2026-08-04" 看似简单,但在 Safari 和部分旧 Chrome 中,日历控件不会重新渲染,用户仍能看到并点选被禁用的日期。真正可靠的方式只有:
-
input.setAttribute('min', '2026-08-04')—— 触发 DOM 属性变更,强制 UI 重绘 - 或在赋值后手动触发重绘:
input.dispatchEvent(new Event('input', { bubbles: true }))
注意:如果 input 当前已有值且超出新范围,仅改 min/max 不会影响已存在的 value,必须额外判断并重置。
服务端校验不可省略,且必须独立于前端逻辑
所有客户端限制都可被绕过:开发者工具修改 DOM、curl 提交、甚至直接数据库写入。服务端收到日期字段时,必须按相同规则二次解析与校验:
- 验证格式是否为
^\d{4}-\d{2}-\d{2}$ - 解析后做真实日期比较(不能字符串比,避免
"2026-1-1" > "2026-01-01"这类陷阱) - 拒绝任何超出业务定义范围的值,哪怕前端看起来“已限制”
最易被忽略的一点:日期字段常被当作字符串透传,没做类型转换就直接入库或参与计算,导致逻辑错误。服务端拿到的永远是字符串,必须先 parse 成日期对象再比。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











