最近遇到,iOS 上的 safati 的一個雷,原來在 <input type='date'> 中的 change 上面定義上跟其他瀏覽器有點不同!
在前端處理日期輸入驗證時,我們通常會監聽 <input type="date"> 的 change 事件
當使用者選擇完日期後,即執行驗證流程。然而,在 iOS Safari 上
使用 change 監聽日期輸入卻常常造成錯誤或過早觸發,導致錯誤的驗證結果或錯誤提示
change 事件會在 使用者修改完表單欄位並確認變更後 才觸發,一般我都會寫在這事件上面
後來我發現有一些問題,問了GPT才知道會有以下問題
在 iOS Safari 上,<input type="date"> 有兩個特別且公認的問題
問題一:change 事件會「過早觸發」
iOS Safari 的日期選擇器在使用者還未選定日期時,就可能觸發 change。
問題二:value 會自動填入今天日期
解決方案就是改用 blur 讓他跟其他瀏覽器都維持一致的結果
範例程式碼:
input.addEventListener("blur", function () {
let raw = this.value;
if (!raw) return; // iOS 使用者沒選日期 → 不檢查
// ...其餘格式化與 min/max 驗證...
});
這邊是我判斷讓客戶必須選取只有明天跟加上兩周的日期
function TwoWeekCheck() {
var input = document.getElementById("txtBookingDate");
var today = new Date();
var twoWeeksLater = new Date();
twoWeeksLater.setDate(today.getDate() +14);
// 明天
var tomorrow = new Date();
tomorrow.setDate(today.getDate() + 1);
input.min = formatDate(tomorrow);
input.max = formatDate(twoWeeksLater);
const inputDate = document.querySelector("input[type='date']");
// 使用者選完日期後才會觸發 blur,最安全
inputDate.addEventListener("blur", function () {
let raw = this.value;
// iOS Safari 若僅打開選擇器但未選日期 → value會是空,不要驗證
if (!raw) return;
// 若是未補零的格式,補成 yyyy-mm-dd
let parts = raw.split("-");
if (parts.length !== 3) return;
const y = parts[0];
const m = parts[1].padStart(2, "0");
const d = parts[2].padStart(2, "0");
const val = `${y}-${m}-${d}`;
const min = this.getAttribute("min");
const max = this.getAttribute("max");
if ((min && val < min) || (max && val > max)) {
toastr.error(`日期必須在 ${min} ~ ${max} 之間`);
this.value = "";
this.focus();
}
});
結論:
change 在 iOS Safari 的 <input type="date"> 上是 "不可靠的",尤其在 input type='date'
這邊筆記一下,之後印象比較深刻