ใช้ Event beforeunload บน window หรือ body เพื่อแจ้งเตือนผู้ใช้ก่อนออกจากหน้า/รีโหลด เมื่อมีข้อมูลในฟอร์มที่ยังไม่บันทึก สมัยใหม่ Browser แสดงข้อความมาตรฐาน (Security) ไม่ให้ Custom Message ได้แล้ว แต่ยัง Cancel ได้โดย return ค่า (Legacy) หรือ event.preventDefault()
ตัวอย่างโค้ด
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Unsaved Changes Alert</title>
<style>
body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; }
input { margin: 10px; }
</style>
</head>
<body>
<h1>แจ้งเตือนการเปลี่ยนแปลงที่ยังไม่บันทึกในฟอร์ม</h1>
<form id="myForm">
Username <input type="text" name="username" /><br />
Password <input type="password" name="password" /><br />
<button type="submit">ส่งข้อมูล</button>
<button type="button" id="resetBtn">ล้างฟอร์ม</button>
</form>
<br />
<p id="status">ลองแก้ไขฟิลด์ แล้วรีโหลดหน้า (F5) หรือปิดแท็บ</p>
<script>
const form = document.getElementById("myForm");
const status = document.getElementById("status");
let isDirty = false;
// ติดตามการเปลี่ยนแปลง
form.addEventListener("input", () => {
isDirty = true;
status.textContent = "⚠️ มีการเปลี่ยนแปลงที่ยังไม่บันทึก";
status.style.color = "orange";
});
// Submit = บันทึกแล้ว
form.addEventListener("submit", (e) => {
e.preventDefault();
isDirty = false;
status.textContent = "✅ บันทึกแล้ว";
status.style.color = "green";
});
// Reset = ล้าง
document.getElementById("resetBtn").addEventListener("click", () => {
form.reset();
isDirty = false;
status.textContent = "🔄 ล้างฟอร์มแล้ว";
status.style.color = "blue";
});
// Before Unload
window.addEventListener("beforeunload", (event) => {
if (isDirty) {
event.preventDefault(); // มาตรฐานใหม่
event.returnValue = ""; // Legacy (Chrome/FF ต้องการ)
// Browser จะแสดง Dialog มาตรฐานของตัวมัน
// (ไม่สามารถ custom message ได้แล้ว เพื่อ Security)
}
});
</script>
</body>
</html>
ผลลัพธ์

ลองรีโหลด (F5) หลังแก้ไขฟิลด์:

รายละเอียด beforeunload
| Browser | Behavior |
|---|---|
| Chrome / Edge / Firefox (Modern) | แสดง Dialog มาตรฐาน "คุณแน่ใจหรือไม่ว่าต้องการออกจากหน้านี้?" ไม่แสดง Custom Message |
| Safari (เก่า) | อาจแสดง Custom Message ได้ (Deprecated) |
| Mobile Browsers | รองรับแตกต่างกัน บางตัวไม่แสดง Dialog |
Best Practices
- ตั้ง Flag
isDirtyเฉพาะเมื่อมีการเปลี่ยนแปลงจริง (input, change) - Reset Flag เมื่อ Submit สำเร็จ หรือ Reset ฟอร์ม
- ไม่ควรใช้
alert(),confirm()ใน beforeunload (Browser บล็อก) - ทดสอบบน Mobile (iOS Safari, Chrome Android) — พฤติกรรมต่างกัน
- พิจารณา Auto-save (Draft) ลง localStorage/IndexedDB แทนการเตือน
การใช้งานกับ SPA (React/Vue/Svelte)
// React: ใช้ useEffect
useEffect(() => {
const handler = (e) => {
if (isDirty) {
e.preventDefault();
e.returnValue = "";
}
};
window.addEventListener("beforeunload", handler);
return () => window.removeEventListener("beforeunload", handler);
}, [isDirty]);
// React Router: ใช้ Prompt component (deprecated) หรือ custom blocker
⚠️ ข้อจำกัด
- ไม่ทำงานถ้าผู้ใช้ Kill Process / Crash Browser
- ไม่ทำงานกับ
window.close()(window ที่เปิดด้วย window.open) - บาง Browser บล็อก Dialog ถ้าไม่มี User Interaction ก่อนหน้า