มีการโหลดเหตุการณ์ข้ามเบราว์เซอร์เมื่อคลิกปุ่มย้อนกลับหรือไม่


185

สำหรับเบราว์เซอร์ที่สำคัญทั้งหมด (ยกเว้น IE) onloadเหตุการณ์JavaScript จะไม่เริ่มทำงานเมื่อหน้าโหลดเนื่องจากการทำงานของปุ่มย้อนกลับซึ่งจะเริ่มทำงานเมื่อโหลดหน้าเว็บครั้งแรกเท่านั้น

มีใครบางคนชี้ให้ฉันดูตัวอย่างโค้ดข้ามเบราว์เซอร์ (Firefox, Opera, Safari, IE, …) ที่แก้ปัญหานี้ได้หรือไม่? ฉันคุ้นเคยกับpageshowเหตุการณ์ของ Firefox แต่น่าเสียดายที่ Opera และ Safari ไม่ได้ใช้สิ่งนี้


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

2
@romkyns: ความคิดเห็นของคุณไม่เกี่ยวข้องกับคำถามนี้ เมื่อเบราว์เซอร์ไม่เรียกคืนสถานะ JS / DOM เบราว์เซอร์จะดำเนินการเหตุการณ์โหลด
Nickolay

ปุ่มย้อนกลับประวัติ iOS 5+ แก้ไขได้ที่นี่stackoverflow.com/a/12652160/1090395
Mladen Janjetovic

คำตอบ:


117

พวกฉันพบว่า JQuery มีผลเพียงอย่างเดียว: หน้าจะโหลดใหม่เมื่อกดปุ่มย้อนกลับ สิ่งนี้ไม่เกี่ยวกับ " พร้อม "

มันทำงานอย่างไร JQuery เพิ่มตัวฟังเหตุการณ์onunload

// http://code.jquery.com/jquery-latest.js
jQuery(window).bind("unload", function() { // ...

โดยค่าเริ่มต้นมันไม่ทำอะไรเลย แต่ดูเหมือนว่าจะมีการรีโหลดใน Safari, Opera และ Mozilla - ไม่ว่าตัวจัดการเหตุการณ์จะประกอบด้วยอะไร

[ แก้ไข (Nickolay) : นี่คือเหตุผลว่าการทำงานวิธีการที่: webkit.org , developer.mozilla.org โปรดอ่านบทความเหล่านั้น (หรือบทสรุปของฉันในคำตอบแยกต่างหากด้านล่าง) และพิจารณาว่าคุณต้องทำสิ่งนี้จริงๆและทำให้หน้าโหลดช้าลงสำหรับผู้ใช้ของคุณ]

ไม่เชื่อหรอ ลองสิ่งนี้:

<body onunload=""><!-- This does the trick -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

คุณจะเห็นผลลัพธ์ที่คล้ายกันเมื่อใช้ JQuery

คุณอาจต้องการเปรียบเทียบกับสิ่งนี้โดยไม่ต้องโหลด

<body><!-- Will not reload on back button -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

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

3
สิ่งนี้ทำงานได้ดี (อย่าลืมส่วน onunload = "" มิฉะนั้นจะไม่ทำงานบน ff3): <body onload = "alert ('onload');" onunload = "">
Wadih M.

3
นี่เป็นเพราะเบราว์เซอร์สันนิษฐานว่าหน้าเว็บนั้นไม่สามารถทำการลบได้หากมีonunloadตัวจัดการ (หน้านั้นได้ทำลายทุกอย่างแล้วทำไมต้องแคชด้วย)
Casey Chu

14
คำตอบดูเหมือนว่าจะไม่ทำงานในเบราว์เซอร์ที่ทันสมัย ​​- ตรวจสอบใน Chrome และ Opera ล่าสุด
แอนดรูว์

10
มันใช้งานไม่ได้ใน iPad Safari ... ได้โปรดยกเลิกการทำเครื่องหมายว่านี่เป็นคำตอบ
xus

74

เบราว์เซอร์ที่ทันสมัยบางตัว (Firefox, Safari และ Opera แต่ไม่ใช่ Chrome) สนับสนุนแคช "back / forward" พิเศษ (ฉันจะเรียกมันว่า bfcache ซึ่งเป็นคำที่ Mozilla คิดค้นขึ้นมา) เกี่ยวข้องกับเมื่อผู้ใช้นำทางกลับมา ซึ่งแตกต่างจากแคชปกติ (HTTP) มันจะจับภาพสถานะที่สมบูรณ์ของหน้า (รวมถึงสถานะของ JS, DOM) การทำเช่นนี้ช่วยให้สามารถโหลดหน้าเว็บได้เร็วขึ้นและเหมือนกับที่ผู้ใช้ทิ้งไว้

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

นี่คือสาเหตุที่การเพิ่มตัวจัดการ "unload" หยุดหน้าจากการถูกเก็บไว้ใน bfcache (ทำให้ช้าลงเพื่อนำทางกลับไปที่) - ตัวจัดการ unload สามารถดำเนินการทำความสะอาดซึ่งอาจทำให้หน้าไม่สามารถทำงานได้

สำหรับหน้าเว็บที่จำเป็นต้องรู้เมื่อมีการนำทางไป / กลับไปที่ Firefox 1.5+ และเวอร์ชันของ Safari พร้อมด้วยการแก้ไขข้อผิดพลาด 28758สนับสนุนกิจกรรมพิเศษที่เรียกว่า "pageshow" และ "pagehide"

อ้างอิง:


มันเจ๋งมาก ตอนนี้ฉันอยู่ในสถานการณ์ที่ไม่ได้บันทึกกิจวัตรของฉันใน bfcache มีสถานการณ์ใดบ้างที่คุณอาจคาดหวังสิ่งนั้น?
Benson

1
@Benson: สาเหตุที่เป็นไปได้เมื่อ Firefox จะไม่บันทึกหน้าเว็บของคุณใน bfcache มีการระบุไว้ในหน้า dev.mo ที่ฉันเชื่อมโยง ฉันไม่คิดว่าเป็นไปได้ที่จะบันทึกหน้าเว็บเป็น bfcache แต่ไม่ได้บันทึกสถานะ DOM บางอย่าง
Nickolay

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

@Greg: คุณหมายถึงเป็นนักพัฒนาที่ควบคุมหน้าเว็บหรือไม่ ปิดการร้องขอ ajax จากผู้ฟัง 'pageshow'
Nickolay

มีความคิดเห็นเกี่ยวกับวิธีใช้ jQuery และรับการสนับสนุน bfcache อย่างรวดเร็วหรือไม่
Alex Black

31

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

หลังจากการทดสอบบางอย่างฉันพบว่า ReadyState ขององค์ประกอบในหน้าเว็บที่ถูกคลิกกลับไม่ได้ 'โหลด' แต่ 'สมบูรณ์' การเพิ่ม|| element.readyState == 'complete'คำสั่งตามเงื่อนไขของฉันแก้ไขปัญหาของฉันได้

แค่คิดว่าฉันจะแบ่งปันสิ่งที่ค้นพบของฉันหวังว่าพวกเขาจะช่วยเหลือคนอื่น

แก้ไขเพื่อความสมบูรณ์

รหัสของฉันดูดังนี้:

script.onreadystatechange(function(){ 
   if(script.readyState == 'loaded' || script.readyState == 'complete') {
      // call code to execute here.
   } 
});

ในตัวอย่างโค้ดด้านบนตัวแปรสคริปต์เป็นองค์ประกอบสคริปต์ที่สร้างขึ้นใหม่ซึ่งถูกเพิ่มไปยัง DOM


7
คุณเพิ่มนี่ที่ไหน และคุณได้อะไรที่จะยิงหลังจากที่ผู้ใช้กลับมา? โปรดแสดงรหัสให้เราดู!
Keerigan

คุณหมายถึงอะไรเมื่อคุณพูดว่า "คำสั่งตามเงื่อนไขของฉัน"?
Phillip Senn

1
@Phillip คำสั่งแบบมีเงื่อนไขเป็นคำสั่ง if
Brian Heese

22

ตกลงนี่เป็นคำตอบสุดท้ายโดยอ้างอิงจากวิธีแก้ปัญหาเบื้องต้นของ ckramer และตัวอย่างของ palehorse ที่ใช้ได้กับเบราว์เซอร์ทั้งหมดรวมถึง Opera ถ้าคุณตั้งค่า history.navigationMode เป็น 'Compatible' ฟังก์ชั่นที่พร้อมใช้งานของ jQuery จะเปิดใช้งานการทำงานของปุ่มย้อนกลับใน Opera และเบราว์เซอร์หลักอื่น ๆ

หน้านี้มีข้อมูลเพิ่มเติม

ตัวอย่าง:

history.navigationMode = 'compatible';
$(document).ready(function(){
  alert('test');
});

ฉันทดสอบสิ่งนี้ใน Opera 9.5, IE7, FF3 และ Safari และทำงานได้ในทุกอย่าง


2
เห็นได้ชัดว่ามันใช้เวลาสักพัก (ประมาณ 5.5 ปี) แต่มันก็คุ้มค่าที่จะสังเกตว่าลิงค์ของคุณเสียชีวิตแล้ว
Jeff

2
วิธีนี้ไม่ได้ผลสำหรับฉัน ฉันมีปัญหานี้ใน Firefox ล่าสุด (45.0.1)
Armin

6

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

<input type='hidden' id='dirty'>

<script>
$(document).ready(function() {
  if ($('#dirty').val()) {
    // ... reload the page or specific divs only
  }
  // when something modifies a div that needs to be refreshed, set dirty=1
  $('#dirty').val('1');
});
</script>

และมันจะทริกเกอร์อย่างถูกต้องเมื่อใดก็ตามที่ฉันคลิกปุ่มย้อนกลับ


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

เบราว์เซอร์ใดที่ใช้ไม่ได้กับหน้าเว็บในลักษณะนี้
Justin

4

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


4

ฉันคิดว่านี่น่าจะเป็น "onunload" ไม่ใช่การโหลดหน้าเว็บเนื่องจากเราไม่ได้พูดถึงการยิงเหตุการณ์เมื่อกดปุ่ม "ย้อนกลับ" หรือไม่ $ document.ready () สำหรับกิจกรรมที่ต้องการในการโหลดหน้าไม่ว่าคุณจะไปที่หน้านั้นได้อย่างไร (เช่นเปลี่ยนเส้นทางเปิดเบราว์เซอร์ไปยัง URL โดยตรง ฯลฯ ) ไม่ใช่เมื่อคลิก "ย้อนกลับ" เว้นแต่ว่าคุณกำลังพูดถึง เกี่ยวกับสิ่งที่จะยิงในหน้าก่อนหน้าเมื่อโหลดอีกครั้ง และฉันไม่แน่ใจว่าหน้าเว็บไม่ได้รับการแคชเนื่องจากฉันพบว่า Javascript ยังคงอยู่แม้ว่าจะมีการรวม $ document.ready () ไว้ในก็ตาม เราต้องกด Ctrl + F5 เมื่อแก้ไขสคริปต์ของเราที่มีเหตุการณ์นี้เมื่อใดก็ตามที่เราแก้ไขพวกเขาและเราต้องการทดสอบผลลัพธ์ในหน้าของเรา

$(window).unload(function(){ alert('do unload stuff here'); }); 

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


4

ฉันสามารถยืนยัน ckramer ว่าเหตุการณ์ที่พร้อมของ jQuery ทำงานใน IE และ FireFox นี่คือตัวอย่าง:

<html>
<head>
    <title>Test Page</title>
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
    <script type="text/javascript">
            $(document).ready(function () {
               var d = new Date();
               $('#test').html( "Hi at " + d.toString() );
            });
    </script>
</head>
<body>
    <div id="test"></div>
    <div>
        <a href="http://www.google.com">Go!</a>
    </div>
</body>
</html>

4

สำหรับผู้ที่ไม่ต้องการใช้ห้องสมุด jQuery ทั้งหมดฉันแยกการใช้งานในรหัสแยกต่างหาก มันใหญ่เพียง 0,4 KB

คุณสามารถค้นหารหัสพร้อมกับบทช่วยสอนภาษาเยอรมันได้ในวิกินี้: http://www.easy-coding.de/wiki/html-ajax-und-co/onload-event-cross-browser-kompatibler-domcontentloaded.html


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

3

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


6
เวลานานในภายหลังreadyดูเหมือนจะไม่ถูกเรียกใช้ใน Firefox เมื่อใช้ปุ่มย้อนกลับ ดูคำตอบของ Nickolayด้วย
Arjan

2

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


2

ฉันลองวิธีแก้ปัญหาจาก Bill โดยใช้ $ (เอกสาร) พร้อม ... แต่ตอนแรกมันไม่ทำงาน ฉันค้นพบว่าหากวางสคริปต์หลังส่วน html สคริปต์จะไม่ทำงาน หากเป็นส่วนหัวมันจะทำงาน แต่ใน IE เท่านั้น สคริปต์ไม่ทำงานใน Firefox


1

ตกลงฉันลองและใช้งานได้กับ Firefox 3, Safari 3.1.1 และ IE7 แต่ไม่ใช่ใน Opera 9.52
หากคุณใช้ตัวอย่างที่แสดงด้านล่าง (ตามตัวอย่างของ palehorse) คุณจะได้รับกล่องข้อความแจ้งเตือนปรากฏขึ้นเมื่อหน้าแรกโหลด แต่ถ้าคุณไปที่ URL อื่นแล้วกดปุ่มย้อนกลับเพื่อกลับไปที่หน้านี้คุณจะไม่ได้รับกล่องข้อความแจ้งเตือนปรากฏขึ้นใน Opera (แต่คุณใช้เบราว์เซอร์อื่น)

อย่างไรก็ตามฉันคิดว่านี่ใกล้พอแล้วสำหรับตอนนี้ ขอบคุณทุกคน!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<meta http-equiv="expires" content="0">
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready( 
                    function(){
                      alert('test');
                    }
                 );
</script>
</head>
<body>
<h1>Test of the page load event and the Back button using jQuery</h1>
</body>
</html>

1

เหตุการณ์ยกเลิกการโหลดไม่ได้ทำงานได้ดีใน IE 9 ฉันพยายามกับกรณีที่โหลด (onload ()) ดีก็คือการทำงานในIE 9และFF5

ตัวอย่าง:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    jQuery(window).bind("load", function() {
        $("[name=customerName]").val('');
    });
</script>
</head>
<body>
    <h1>body.jsp</h1>
    <form action="success.jsp">
        <div id="myDiv">

        Your Full Name: <input name="yourName" id="fullName"
            value="Your Full Name" /><br> <br> <input type="submit"><br>

        </div>

    </form>
</body>
</html>

0

ฉันใช้เทมเพลต html ในไฟล์ custom.js ของแม่แบบนี้มีฟังก์ชั่นดังนี้:

    jQuery(document).ready(function($) {

       $(window).on('load', function() {
          //...
       });

    });

แต่ฟังก์ชั่นนี้ใช้งานไม่ได้เมื่อฉันกลับไปหลังจากไปหน้าอื่น

ดังนั้นฉันลองทำสิ่งนี้และใช้งานได้:

    jQuery(document).ready(function($) {
       //...
    });

   //Window Load Start
   window.addEventListener('load', function() {
       jQuery(document).ready(function($) {
          //...
       });
   });

ตอนนี้ฉันมีฟังก์ชั่น 2 "พร้อม" แต่มันก็ไม่ได้ทำให้เกิดข้อผิดพลาดและหน้าเว็บทำงานได้ดีมาก

อย่างไรก็ตามฉันต้องประกาศว่าได้ทำการทดสอบบน Windows 10 - Opera v53 และ Edge v42 แต่ไม่มีเบราว์เซอร์อื่น โปรดจำไว้ว่า ...

หมายเหตุ: รุ่น jquery เป็น 3.3.1 และรุ่นโยกย้ายเป็น 3.0.0

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