註冊頁面中,輸入框綁定 onfocus 顯示提示、onblur 驗證格式,但事件無響應,控制台無報錯,驗證邏輯不執行。
// 錯誤代碼片段
function showWrong() {
var msg = document.getElementById("userMsg");
var name = document.getElementById("form").userName; // ❌ 此處報錯:Cannot read property 'userName' of null
// ...
}
原因:HTML 中 <form> 標籤缺少 id="form" 屬性,導致 document.getElementById("form") 返回 null,後續訪問 .userName 拋出異常,中斷函數執行,表現為「事件無反應」。
<form action="" onsubmit="return check();" id="form">
<input type="text" name="userName" onfocus="showHow();" onblur="showWrong();" />
<span id="userMsg"></span>
...
</form>
// 方式一:通過 name 獲取 (表單有 name 時)
var form = document.forms["formName"]; // 或 document.formName
var name = form.userName;
// 方式二:通過元素關係獲取 (無需 form id)
function showWrong(inputElement) { // 將 this 傳入
var msg = document.getElementById("userMsg");
var name = inputElement; // 直接是輸入框元素
// ...
}
// HTML
<input ... onblur="showWrong(this);" />
// HTML
<form id="regForm" novalidate>
<input type="text" name="userName" id="userName" data-rule="username">
<span class="msg" data-for="userName"></span>
...
</form>
// JS (DOMContentLoaded 中綁定)
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('regForm');
const fields = form.querySelectorAll('[data-rule]');
fields.forEach(input => {
const rule = input.dataset.rule;
const msgEl = form.querySelector(`[data-for="${input.id}"]`);
input.addEventListener('focus', () => showHint(rule, msgEl));
input.addEventListener('blur', () => validate(rule, input, msgEl));
});
form.addEventListener('submit', (e) => {
let valid = true;
fields.forEach(input => {
if (!validate(input.dataset.rule, input, form.querySelector(`[data-for="${input.id}"]`))) {
valid = false;
}
});
if (!valid) e.preventDefault();
});
});
const validators = {
username: (value) => {
if (!value) return "用戶名不能為空";
if (value.length < 4) return "用戶名長度須大於4位";
if (value.length > 16) return "用戶名長度須在16位以內";
if (!/^[a-zA-Z]\w{3,15}$/.test(value)) return "首位為字母的4-16位數字、字母、下劃線";
return null; // 通過
},
password: (value) => {
if (!value) return "密碼不能為空";
if (value.length < 4) return "密碼長度須大於4位";
if (value.length > 10) return "密碼長度須在10位以內";
if (!/^[a-zA-Z_]{4,10}$/.test(value)) return "4-10個字母和下劃線";
return null;
}
};
function validate(rule, input, msgEl) {
const error = validators[rule](input.value);
if (error) {
msgEl.textContent = error;
msgEl.className = "msg error";
input.classList.add("invalid");
return false;
} else {
msgEl.textContent = "";
msgEl.className = "msg";
input.classList.remove("invalid");
return true;
}
}
function showHint(rule, msgEl) {
const hints = {
username: "首位為字母的4-16位數字、字母、下劃線",
password: "4-10個字母和下劃線"
};
msgEl.textContent = hints[rule] || "";
msgEl.className = "msg hint";
}
| 誤區 | 後果 | 修正 |
|---|---|---|
| form 缺少 id 但 JS 用 getElementById("form") | 返回 null,後續訪問屬性拋異常,靜默失敗 | 添加 id="form" 或改用 document.forms[name]/input.form |
| 內聯事件處理函數中 this 指向 window | 無法獲取觸發元素 | 傳入 this: onblur="check(this)" 或改用 addEventListener |
| 驗證邏輯與 DOM 操作強耦合 | 難維護、難測試、難復用 | 提取純函數 validators,UI 邏輯分離 |
| 正則未轉義特殊字符 (如 \w 包含下劃線) | 規則不符預期 | 確認正則語義,\w = [a-zA-Z0-9_] |
事件「無反應」實為 **JS 運行時異常中斷**,根因是 document.getElementById("form") 找不到元素。修復:為 <form> 添加 id="form" 或改用 input.form/document.forms[name] 獲取表單。進階建議:採用 addEventListener、data-* 屬性驅動、規則引擎分離,構建可維護、可測試的現代表單驗證體系。