Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> JavaScript

แจ้งเตือนการเปลี่ยนแปลงที่ยังไม่บันทึกในฟอร์ม (beforeunload) ใน JavaScript


ใช้ 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>

ผลลัพธ์

แจ้งเตือนการเปลี่ยนแปลงที่ยังไม่บันทึกในฟอร์ม (beforeunload) ใน JavaScript

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

แจ้งเตือนการเปลี่ยนแปลงที่ยังไม่บันทึกในฟอร์ม (beforeunload) ใน JavaScript

รายละเอียด beforeunload

BrowserBehavior
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 ก่อนหน้า