必须用 type="date" 才能可靠校验,min/max 仅对其生效;通过 change 事件动态设置起止日期的 min/max 约束,并在清空时移除对应属性;提交前调用 checkvalidity() 主动校验。

起止日期输入框必须用 type="date" 才能可靠校验
浏览器原生日期控件(input type="date")自带基础格式和范围约束,不用 JS 也能拦截明显非法输入(比如 2023-02-30)。如果用 type="text" + 自定义格式(如 YYYY/MM/DD),校验逻辑就得全手写,且无法阻止用户粘贴无效字符串。
关键点:min 和 max 属性只对 type="date" 生效;对 text 或其他类型完全无作用。
-
start输入框加id="start-date",end加id="end-date",方便后续 JS 绑定 - 初始时可不设
min/max,等一个日期选中后再动态设置另一个的约束 - 注意:Safari 14.1+ 才支持
type="date"的完整行为,旧版需降级处理(见下节)
用 change 事件联动设置 min/max
仅靠静态 min 和 max 不够——起止日期是相互依赖的。比如选了 start-date 后,end-date 的 min 应该设为该值;反之亦然。必须用 JS 动态控制。
示例逻辑:
document.getElementById('start-date').addEventListener('change', function() {
const start = this.value;
const endInput = document.getElementById('end-date');
if (start && !endInput.hasAttribute('min')) {
endInput.min = start; // end 不能早于 start
}
});
document.getElementById('end-date').addEventListener('change', function() {
const end = this.value;
const startInput = document.getElementById('start-date');
if (end && !startInput.hasAttribute('max')) {
startInput.max = end; // start 不能晚于 end
}
});
- 用
change而非input:避免频繁触发,且确保用户已确认选择 - 检查
hasAttribute是为了防止多次绑定后重复覆盖min/max,导致约束过严 - 如果用户清空一个字段,应同步移除另一个字段的对应属性(例如清空
start-date,就removeAttribute('min'))
提交前用 checkValidity() 主动触发校验
即使设置了 min/max,浏览器也不会在表单提交前自动比对两个字段的逻辑关系(比如 end setCustomValidity()。
常见错误:只监听 change,但用户直接点击提交按钮时没校验。
- 在
form的submit事件里取两个value,转成Date对象比较 - 若
new Date(end) ,则对 <code>end-date调用.setCustomValidity('结束日期不能早于开始日期') - 记得在每次输入后调用
.setCustomValidity('')清除旧错误,否则会持续阻断提交 - 注意:空字符串会被
new Date('')解析为 Invalid Date,要先判断value是否非空
Safari 旧版或禁用 JS 时的兜底方案
部分老 Safari(type="date",回退为 text;JS 被禁用时所有动态逻辑失效。这时只能靠服务端校验,但前端至少要提供清晰提示。
- 给两个输入框都加
required属性,保证非空 - 在 label 旁用 (格式:YYYY-MM-DD) 提示格式,降低误填概率
- 不要依赖 placeholder 做格式说明——iOS Safari 中
type="date"会忽略它 - 如果项目必须支持极旧环境,建议用轻量级 datepicker 库(如 flatpickr),但要注意它不改变原生
input的type,仍需手动同步min/max
真正容易被忽略的是:用户可能绕过 UI 直接修改 DOM 属性(比如删掉 min),或者用开发者工具改 value。这类操作无法被前端完全拦截,所以服务端校验永远不可省略。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











