เหตุการณ์การออกจากหน้าสกัดกั้น


117

เมื่อแก้ไขเพจในระบบของฉันผู้ใช้อาจตัดสินใจนำทางไปยังเว็บไซต์อื่นและการทำเช่นนั้นอาจสูญเสียการแก้ไขทั้งหมดที่ไม่ได้บันทึกไว้

ฉันต้องการสกัดกั้นความพยายามที่จะไปที่หน้าอื่นและแจ้งให้ผู้ใช้แน่ใจว่าต้องการให้สิ่งนี้เกิดขึ้นเนื่องจากอาจสูญเสียงานปัจจุบัน

Gmail ทำในลักษณะที่คล้ายกันมาก ตัวอย่างเช่นเขียนอีเมลใหม่เริ่มพิมพ์ลงในเนื้อหาข้อความและป้อนตำแหน่งใหม่ในแถบที่อยู่ (พูดว่า twitter.com หรืออะไรก็ได้) มันจะถามว่า "แน่ใจหรือ"

แนวคิดวิธีการจำลองสิ่งนี้? ฉันกำหนดเป้าหมาย IE8 แต่ต้องการใช้งานร่วมกับ FF & Chrome ด้วย


คำตอบ:


154

คล้ายกับคำตอบของ Ghommey แต่ยังรองรับ IE และ Firefox เวอร์ชันเก่าด้วย

window.onbeforeunload = function (e) {
  var message = "Your confirmation message goes here.",
  e = e || window.event;
  // For IE and Firefox
  if (e) {
    e.returnValue = message;
  }

  // For Safari
  return message;
};

1
คุณช่วยอธิบายบรรทัดแรก (ข้อความ var = ... ) ได้ไหม ฉันไม่รู้ว่าเครื่องหมายจุลภาคและนิพจน์ที่สองกำลังทำอะไร
mtmurdock

7
@mtmurdock นั่นเป็นเพียงไวยากรณ์ Javascript เพื่อประกาศตัวแปรหลายตัว var foo, bar;เหมือนกับvar foo; var bar;
T Nguyen

4
@mtmurdock คำสั่งที่สอง " var e = e || window.event;" หมายถึงตั้งค่าeเท่ากับพารามิเตอร์e (ถ้าเป็นจริง) หรือหน้าต่างเหตุการณ์ถ้าไม่ใช่ความจริง จะไม่เป็นจริงหากพารามิเตอร์eเป็นโมฆะ
T Nguyen

3
@Blieque addEventListener ไม่รองรับใน IE8 อย่าแก้ไขคำตอบของผู้อื่นโดยไม่ได้อ่านคำถาม
Eli Gray

2
ไม่ทำงานอีกต่อไปใน Chrome (เลิกใช้งานแล้ว): developers.google.com/web/updates/2016/04/…
Micha Schwab

25

ดูบทความนี้ คุณสมบัติที่คุณกำลังมองหาคือonbeforeunload

รหัสตัวอย่าง:

  <script language="JavaScript">
  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    return "You have attempted to leave this page.  If you have made any changes to the fields without clicking the Save button, your changes will be lost.  Are you sure you want to exit this page?";
  }
</script>

2
มีวิธีใดในการระบุว่าผู้ใช้เลือกใช้ตัวเลือก "ออกจากหน้านี้" แทนที่จะเป็น "อยู่ในหน้านี้"
Shilpa Soni

@ShilpaSoni คุณจะได้รับเหตุการณ์การยกเลิกการโหลดในภายหลังdeveloper.mozilla.org/en-US/docs/Web/API/Window/unload_eventแต่ฉันไม่คิดว่าจะมีวิธีซิงโครนัส
scipilot

6

แทนที่จะเป็นป๊อปอัปการยืนยันที่น่ารำคาญมันเป็นการดีที่จะชะลอการทิ้งไว้เพียงเล็กน้อย (เรื่องของมิลลิวินาที) เพื่อจัดการการโพสต์ข้อมูลที่ไม่ได้บันทึกไปยังเซิร์ฟเวอร์ได้สำเร็จซึ่งฉันจัดการสำหรับไซต์ของฉันโดยใช้การเขียนข้อความจำลองลงในคอนโซลดังนี้:

window.onbeforeunload=function(e){
  // only take action (iterate) if my SCHEDULED_REQUEST object contains data        
  for (var key in SCHEDULED_REQUEST){   
    postRequest(SCHEDULED_REQUEST); // post and empty SCHEDULED_REQUEST object
    for (var i=0;i<1000;i++){
      // do something unnoticable but time consuming like writing a lot to console
      console.log('buying some time to finish saving data'); 
    };
    break;
  };
}; // no return string --> user will leave as normal but data is send to server

แก้ไข: ดูSynchronous_AJAXและวิธีดำเนินการกับjquery


ฉันชอบทางเลือกนี้สำหรับป๊อปอัป ขอบคุณสำหรับข้อเสนอแนะ Remi
คริสบัลแลนซ์

2
ที่ไม่สมเหตุสมผล -1 javascript จะไม่ถูกเธรดในสิ่งที่คุณกำลังทำคือทำ postRequest จากนั้นหยุดการคำนวณของไซต์ชั่วคราวโดยไม่อนุญาตให้ไม่มีใครทำอะไรเลย (รวมถึง postRequest ของคุณซึ่งในขณะนั้นได้ถูกส่งไปแล้วก่อนที่จะหยุดการคำนวณชั่วคราว)
fmsf

และนั่นคือเหตุผลที่มันใช้งานได้จริง ๆ แล้วคำขอโพสต์ถูกส่งก่อนที่การคำนวณจะหยุดชั่วคราว แต่การปิดกั้นหน้าเล็กน้อยนี้ก่อนที่มันจะถูกทิ้งไว้ทำให้มั่นใจได้ว่ามีเวลาเพียงพอสำหรับไคลเอนต์เบราว์เซอร์ (ไม่ใช่จาวาสคริปต์) ในการส่งคำขอนี้ให้เสร็จสิ้นอย่างถูกต้อง . ฉันสังเกตเห็นว่าเมื่อฉันส่งคำขอเท่านั้น (โดยไม่มีการบล็อก) และออกจากหน้านี้ทันทีคำขอจะไม่ถูกส่งเสมอไป
Remi

6
ฉันจะไม่ใช้สิ่งนั้นในการผลิต console.log ไม่ใช่ crossbrowser แต่ละ postRequest ต้องทนทุกข์ทรมานจากความล่าช้าของรายการก่อนหน้า (ซึ่งหมายความว่าเพจจะค้างอยู่ที่นั่นตลอดระยะเวลาของคำขอที่กำหนดเวลาวนซ้ำของคุณ) คำขอไม่ได้เริ่มต้นพร้อมกัน คุณไม่รับประกันว่าจะส่งคำขอของคุณจริงๆ หากฉันถูกบังคับให้เผชิญกับปัญหานี้ฉันจะไปพร้อมกับคำขอ ajax แบบซิงโครนัสหากมีเพียงคำขอเดียว ด้วยการร้องขอหลายครั้งฉันจะใช้คำขอ async ajax และลูปที่ตรวจสอบผลลัพธ์ (ไม่ว่าจะสำเร็จหรือผิดพลาด) จากการเรียกกลับของคำขอ
framp

ฉันไม่รู้ว่า console.log ไม่ใช่ข้ามเบราว์เซอร์และคำขอ Synchronous Ajaxควรเป็นโซลูชันที่ต้องการ (สำหรับคำขอเดียว) สิ่งที่กล่าวถึงSCHEDULED_REQUESTนี้เป็นวัตถุที่รวบรวมข้อมูลที่ไม่เร่งด่วนที่ควรส่งไปยังเซิร์ฟเวอร์เช่นบัฟเฟอร์ของข้อมูลที่รวมคำขอหลายรายการเข้ากับหนึ่งคำขอได้อย่างมีประสิทธิภาพ (แน่นอนว่า URL ของคำขอเหล่านี้เหมือนกัน) การใช้คำขอ Synchronous Ajax ก่อนยกเลิกการโหลดควรแก้ปัญหาข้ามเบราว์เซอร์ดังที่คุณกล่าว ขอบคุณสำหรับความคิดเห็นที่มีค่าของคุณ!
Remi

0

ฉันมีผู้ใช้ที่ไม่ได้กรอกข้อมูลที่จำเป็นทั้งหมด

<cfset unloadCheck=0>//a ColdFusion precheck in my page generation to see if unload check is needed
var erMsg="";
$(document).ready(function(){
<cfif q.myData eq "">
    <cfset unloadCheck=1>
    $("#myInput").change(function(){
        verify(); //function elsewhere that checks all fields and populates erMsg with error messages for any fail(s)
        if(erMsg=="") window.onbeforeunload = null; //all OK so let them pass
        else window.onbeforeunload = confirmExit(); //borrowed from Jantimon above;
    });
});
<cfif unloadCheck><!--- if any are outstanding, set the error message and the unload alert --->
    verify();
    window.onbeforeunload = confirmExit;
    function confirmExit() {return "Data is incomplete for this Case:"+erMsg;}
</cfif>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.