ฉันจะแทนที่กล่องโต้ตอบ OnBeforeUnload และแทนที่ด้วยตัวเองได้อย่างไร


346

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

window.onbeforeunload=handler

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

จนถึงตอนนี้ฉันล้มเหลวและไม่พบใครที่ดูเหมือนจะมีคำตอบ เป็นไปได้ไหม

Javascript ในหน้าของฉัน:

<script type="text/javascript">   
   window.onbeforeunload=closeIt;
</script>

ฟังก์ชั่น closeIt ():

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

การใช้ jQuery และ jqModal ฉันลองสิ่งนี้แล้ว (ใช้กล่องโต้ตอบยืนยันที่กำหนดเอง):

$(window).beforeunload(function() {
        confirm('new message: ' + this.href + ' !', this.href);
        return false;
    });

ซึ่งยังใช้งานไม่ได้ - ฉันไม่สามารถผูกไว้กับเหตุการณ์ beforeunload ได้


1
คุณสามารถให้ตัวอย่างของรหัสปัจจุบันของคุณและสิ่งที่ผลิต?
โอเว่น

โอเว่นถูกต้องแล้ว และเหตุผลที่อยู่เบื้องหลังนี้คือความปลอดภัย การป้องกันการยกเลิกการโหลดหน้าเว็บนั้นมีประโยชน์ในรูปแบบเว็บและเช่นนั้นเว็บไซต์ที่ประสงค์ร้ายอาจหลอกผู้ใช้ให้อยู่ในหน้าเว็บนั้นได้ นั่นเป็นสาเหตุที่เว็บเบราว์เซอร์ใช้ข้อความมาตรฐานและมีกลไกนี้ในการแทรกข้อความที่กำหนดเอง
234 pluckyglen

ดูที่นี่สำหรับข้อมูลเพิ่มเติม: stackoverflow.com/questions/140460
Ben McIntyre

ข้อมูลเพิ่มเติม: stackoverflow.com/questions/7389554/crossbrowser-onbeforeunload/ …
Aelios

1
ไม่สามารถใช้กับโครเมี่ยมได้อ้างอิง: stackoverflow.com/questions/37782104/…
Abhijeet

คำตอบ:


300

คุณไม่สามารถแก้ไขการสนทนาเริ่มต้นสำหรับonbeforeunloadดังนั้นทางออกที่ดีที่สุดของคุณอาจจะทำงานกับมัน

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

นี่คือการอ้างอิงถึงสิ่งนี้จาก Microsoft:

เมื่อสตริงถูกกำหนดให้กับคุณสมบัติ returnValue ของ window.event กล่องโต้ตอบปรากฏขึ้นที่ให้ผู้ใช้ตัวเลือกที่จะอยู่ในหน้าปัจจุบันและรักษาสตริงที่ได้รับมอบหมาย คำสั่งเริ่มต้นที่ปรากฏในกล่องโต้ตอบ "คุณแน่ใจหรือไม่ว่าต้องการออกจากหน้านี้ ... กดตกลงเพื่อดำเนินการต่อหรือยกเลิกเพื่ออยู่ในหน้าปัจจุบัน" ไม่สามารถลบหรือแก้ไขได้

ปัญหาน่าจะเป็น:

  1. เมื่อจะเรียกว่ามันจะใช้เวลาค่าตอบแทนของผู้บริหารเป็นonbeforeunloadwindow.event.returnValue
  2. มันจะแยกค่าส่งคืนเป็นสตริง (ยกเว้นว่ามันจะเป็นโมฆะ)
  3. เนื่องจากfalseจะแยกเป็นสตริง, กล่องโต้ตอบจะยิงซึ่งจากนั้นจะผ่านที่เหมาะสม/truefalse

ผลลัพธ์คือดูเหมือนจะไม่มีวิธีกำหนดfalseให้onbeforeunloadเพื่อป้องกันไม่ให้มีการสนทนาเริ่มต้น

หมายเหตุเพิ่มเติมเกี่ยวกับ jQuery:

  • การตั้งค่าเหตุการณ์ใน jQuery อาจเป็นปัญหาเนื่องจากช่วยให้onbeforeunloadเหตุการณ์อื่น ๆเกิดขึ้นเช่นกัน หากคุณต้องการให้เหตุการณ์การโหลดของคุณเกิดขึ้นฉันจะใช้จาวาสคริปต์ธรรมดา
  • jQuery ไม่มีทางลัดonbeforeunloadดังนั้นคุณต้องใช้bindไวยากรณ์ทั่วไป

    $(window).bind('beforeunload', function() {} );

แก้ไข 09/04/2018 : ข้อความที่กำหนดเองในกล่องโต้ตอบ onbeforeunload ถูกคัดค้านตั้งแต่ chrome-51 (cf: บันทึกประจำรุ่น )


20
ฉันพบว่าตัวอย่าง JQuery ของที่กำหนดในตอนท้ายไม่ให้ทำงานใน firefox ใช้วิธีง่ายๆแทน: window.onbeforeunload = function () {... }
jb

21
เพิ่งทราบว่า Firefox เพิ่งถูกเปลี่ยนแปลงเพื่อให้ข้อความในกล่องโต้ตอบไม่สามารถปรับแต่งได้: bugzilla.mozilla.org/show_bug.cgi?id=588292
David Hammond

15
แต่ Facebook จะให้กล่องโต้ตอบที่กำหนดเองได้อย่างไร ตัวอย่างเช่นไปที่หน้าข้อความตอบกลับข้อความของเพื่อนของคุณจากนั้นก่อนคลิกส่งลองคลิกลิงก์อื่น คุณจะเห็นป๊อปอัพโต้ตอบที่กำหนดเอง
Varun

20
@Varun - ข่าวเก่า แต่ Facebook อาจวางตัวจัดการเหตุการณ์คลิกของจุดยึดทั้งหมดของพวกเขา แต่ถ้าคุณเขียน URL ในเบราว์เซอร์หรือปิดหน้าต่างมันจะกลับไปเป็นวิธีมาตรฐานที่พวกเขาไม่สามารถควบคุมได้
Tabloo Quijico

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

28

สิ่งที่ใช้ได้ผลสำหรับฉันโดยใช้jQueryและทดสอบใน IE8, Chrome และ Firefox คือ:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

เป็นสิ่งสำคัญที่จะไม่ส่งคืนสิ่งใดหากไม่จำเป็นต้องมีพรอมต์เนื่องจากมีความแตกต่างระหว่าง IE กับพฤติกรรมของเบราว์เซอร์อื่น ๆ ที่นี่


สิ่งที่น่าสนใจevent.returnValueคือวิธีการ "อนุมัติ" อย่างเดียวใน IE IE กล่าวต่อไปว่า "ค่าของคุณสมบัตินี้มีความสำคัญมากกว่าค่าที่ส่งคืนโดยฟังก์ชันเช่นผ่านคำสั่งการส่งคืน Microsoft JScript" .. มันจะดีที่จะเห็นความสัมพันธ์ที่รับประกันระหว่างreturn(จากเหตุการณ์) และevent.returnValue..

21

ในขณะที่ไม่มีสิ่งใดที่คุณสามารถทำได้เกี่ยวกับกล่องในบางกรณีคุณสามารถดักคนที่คลิกที่ลิงค์ สำหรับฉันมันคุ้มค่ากับความพยายามสำหรับสถานการณ์ส่วนใหญ่และในฐานะทางเลือกฉันได้ออกจากเหตุการณ์การโหลด

ฉันใช้ Boxy แทน jQuery Dialog มาตรฐานแล้วมันมีให้ที่นี่: http://onehackoranother.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

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

ฉันตัดรหัสออกดังนั้นสิ่งนี้อาจไม่ทำงานตามที่เป็นอยู่


return 'คุณได้ทำการเปลี่ยนแปลงบางอย่างซึ่งคุณอาจต้องการบันทึก' ไม่ได้ผลสำหรับฉัน ฉันต้องเก็บข้อความไว้ในตัวแปรว่า 'warning_message' และกลับมา warning_message ถ้าอย่างนั้นก็ใช้ได้สำหรับฉัน!
Suganya

คุณทดสอบใน IE, Chrome, Firefox หรือไม่
Kiquenet

9

1) ใช้ก่อนโหลดไม่โหลด

2) สิ่งสำคัญคือการหลีกเลี่ยงการดำเนินการคำสั่งส่งคืน ฉันไม่ได้หมายความว่าเพื่อหลีกเลี่ยงการกลับมาจากผู้จัดการของคุณ คุณคืนค่าถูกต้อง แต่คุณทำได้โดยทำให้แน่ใจว่าคุณถึงจุดสิ้นสุดของฟังก์ชันและไม่เรียกใช้คำสั่ง return ภายใต้เงื่อนไขเหล่านี้กล่องโต้ตอบมาตรฐานภายในจะไม่เกิดขึ้น

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


เพียงแค่ FYI ทุกคนที่อ่าน ^ ^ Chrome กำลังเลิกใช้การโทร AJAX แบบซิงโครนัสในช่วงที่ไม่โหลด
morganwebdev

4

ลองวางreturn;แทนข้อความ .. นี่ใช้งานได้กับเบราว์เซอร์ส่วนใหญ่สำหรับฉัน (นี่เป็นการป้องกันการนำเสนอของกล่องโต้ตอบเท่านั้นจริงๆ ๆ )

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}

3
return null จะป้องกันไม่ให้กล่องโต้ตอบเปิด
Brett Weber

1
กลับ null จะไม่ป้องกันการโต้ตอบจากการเปิด ฉันลองใช้ Chrome แล้วไม่ใช่อย่างนั้น
เรย์

2
ฉันสามารถยืนยันความคิดเห็นของ Ray ใน IE ได้เช่นกัน การกลับมาnullจะเปิดกล่องโต้ตอบพร้อมข้อความ "null" อย่างไรก็ตามreturn void(0);จะไม่เปิดกล่องโต้ตอบ
MCattle

1
โดยไม่ใส่คำสั่ง return ใด ๆ ภายในฟังก์ชั่น beforeunload กล่องโต้ตอบจะไม่เปิด
OuuGiii


3

คุณสามารถตรวจสอบว่าผู้ใช้กดปุ่มใด (ตกลงหรือยกเลิก) เนื่องจากฟังก์ชั่น onunload เรียกว่าเมื่อผู้ใช้เลือกที่จะออกจากหน้า แม้ว่าใน funcion นี้ความเป็นไปได้จะถูก จำกัด เนื่องจาก DOM กำลังถูกยุบ คุณสามารถเรียกใช้ javascript ได้ แต่ ajax POST ไม่ได้ทำอะไรดังนั้นคุณไม่สามารถใช้ methode นี้ในการออกจากระบบอัตโนมัติ แต่มีทางออกสำหรับสิ่งนั้น window.open ('logout.php') ดำเนินการใน funcion onunload ดังนั้นผู้ใช้จะออกจากระบบด้วยการเปิดหน้าต่างใหม่

function onunload = (){
    window.open('logout.php');
}

รหัสนี้เรียกว่าเมื่อผู้ใช้ออกจากหน้าหรือปิดหน้าต่างที่ใช้งานและผู้ใช้ออกจากระบบโดย 'logout.php' หน้าต่างใหม่ปิดทันทีเมื่อออกจากระบบ php ประกอบด้วยรหัส:

window.close();

คุณสามารถใช้โพสต์แบบซิงโครนัสในฟังก์ชั่น beforeunload และ unload โดยเฉพาะอย่างยิ่งถ้าคุณต้องการข้อมูลกลับจากเซิร์ฟเวอร์ โค้ด async ใด ๆ ภายในบล็อคเหล่านั้นอาจไม่เสร็จตามเวลาที่หน้าเว็บยกเลิกการโหลด
jemiloii

3

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

ต่อไปนี้เป็นรหัสวิธีแก้ไขปัญหาที่ฉันพบซึ่งฉันเขียนไว้ในหน้าหลักของฉัน

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;


1

สิ่งที่เกี่ยวกับการใช้รุ่นพิเศษของคำสั่ง "ผูก" "หนึ่ง" เมื่อตัวจัดการเหตุการณ์ดำเนินการในครั้งแรกจะถูกลบออกโดยอัตโนมัติเป็นตัวจัดการเหตุการณ์

$(window).one("beforeunload", BeforeUnload);

ค่อนข้างแน่ใจว่านี่คือ. on ("beforeunload"
Sergiu Mindras

2
@SergiuMindras ไม่มัน.one()- ที่แนบตัวฟังเหตุการณ์เพื่อฟังเหตุการณ์ที่เกิดขึ้นเพียงครั้งเดียว: "แนบตัวจัดการกับเหตุการณ์สำหรับองค์ประกอบตัวจัดการจะดำเนินการได้มากที่สุดหนึ่งครั้งต่อองค์ประกอบต่อประเภทเหตุการณ์" api.jquery.com/one
Sean Kendle

0

วิธีการเชิงมุม 9:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

เบราว์เซอร์รองรับและลบข้อความที่กำหนดเอง:

  • Chrome ลบการสนับสนุนสำหรับข้อความที่กำหนดเองใน ver 51 นาที
  • Opera ถูกลบการสนับสนุนสำหรับข้อความที่กำหนดเองใน 38 นาที
  • Firefox ลบการสนับสนุนสำหรับข้อความที่กำหนดเองในเวอร์ชั่น 44.0 นาที
  • Safari ลบการสนับสนุนสำหรับข้อความที่กำหนดเองในเวอร์ชั่น 9.1 นาที
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.