ฉันจะตรวจสอบได้อย่างไรว่าผู้ใช้เข้ามาที่เพจโดยใช้ปุ่มย้อนกลับ?


90

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

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

ปัญหาคือถ้า:

  1. เพจถูกโหลดโดยไม่มีคำอธิบาย
  2. คำอธิบายถูกเพิ่มโดยผู้ใช้
  3. หน้านี้ถูกนำทางออกไปโดยการคลิกลิงก์
  4. ผู้ใช้คลิกปุ่มย้อนกลับ

จากนั้นสิ่งที่แสดง (จากแคชของเบราว์เซอร์) คือเวอร์ชันของเพจที่ไม่มี DIV ที่แก้ไขแบบไดนามิกซึ่งมีคำอธิบายใหม่

นี่เป็นปัญหาใหญ่พอสมควรเนื่องจากผู้ใช้สันนิษฐานว่าการอัปเดตของตนสูญหายและไม่จำเป็นต้องเข้าใจว่าต้องรีเฟรชหน้าเพื่อดูการเปลี่ยนแปลง

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


คำถามนี้แตกต่างจากคำถามที่คุณยกมาอย่างไร
innaM

คำถามคล้ายกัน แต่ฉันคิดว่าสภาพแวดล้อมและด้วยเหตุนี้คำตอบจึงแตกต่างกันฉันอาจคิดผิด การตีความของฉันเกี่ยวกับปัญหาที่อาจแก้ไขได้ด้วยวิธีอื่นคือ: ผู้ใช้คลิกแท็บบนหน้าที่โหลดโดย ajax จากนั้นแท็บอื่นและอื่น ๆ การคลิกปุ่มย้อนกลับจะนำคุณกลับไปยังหน้าอื่นไม่ใช่แท็บก่อนหน้า พวกเขาต้องการย้อนกลับไปที่ "ประวัติ ajax" ภายใน "page history" อย่างน้อยนั่นคือความประทับใจของฉันเกี่ยวกับสิ่งที่ Yahoo Browser History Manager ควรจะทำ ฉันได้รับบางสิ่งบางอย่างที่พื้นฐานมากขึ้น
ทอม

คำตอบที่ยอมรับมีเคล็ดลับ iframe ของคุณ
innaM

คำตอบ:


79

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

<form name="ignore_me">
    <input type="hidden" id="page_is_dirty" name="page_is_dirty" value="0" />
</form>

ในจาวาสคริปต์ของคุณคุณจะต้องมีสิ่งต่อไปนี้:

var dirty_bit = document.getElementById('page_is_dirty');
if (dirty_bit.value == '1') window.location.reload();
function mark_page_dirty() {
    dirty_bit.value = '1';
}

js ที่ sniff ฟอร์มจะต้องดำเนินการหลังจากที่ html ถูกแยกวิเคราะห์อย่างสมบูรณ์ แต่คุณสามารถใส่ทั้งแบบฟอร์มและ js แบบอินไลน์ที่ด้านบนของหน้า (js วินาที) หากเวลาในการตอบสนองของผู้ใช้เป็นปัญหาที่ร้ายแรง


5
"ข้อมูลแบบฟอร์มจะถูกเก็บรักษาไว้ (โดยทั่วไป) ในเบราว์เซอร์" - คุณสามารถขยายได้หรือไม่ มันไม่ได้รับการเก็บรักษาไว้ในบางเบราว์เซอร์? หรือในบางสถานการณ์?
ทอม

4
อันที่จริงให้ฉันเขียนรายการวิธีที่ฉันคิดว่ามันผิดพลาดได้ทั้งหมด (1) Opera คงสถานะเต็มของเพจและจะไม่เรียกใช้ js ซ้ำ (2) หากการตั้งค่าแคชของคุณได้รับการปรับแต่งเพื่อบังคับให้โหลดหน้าจากเซิร์ฟเวอร์บนปุ่มย้อนกลับข้อมูลแบบฟอร์มอาจสูญหายซึ่งเป็นผลดีสำหรับวัตถุประสงค์ของคำถามนี้ (3) เบราว์เซอร์โทรศัพท์มีแคชที่เล็กกว่ามากและเบราว์เซอร์อาจละหน้าออกจากแคชแล้ว (ไม่ใช่ปัญหาสำหรับวัตถุประสงค์เหล่านี้)
Nick White

10
ในบางเบราว์เซอร์แท็กที่ซ่อนอยู่จะไม่ถูกเก็บรักษาไว้ คุณจึงสามารถใช้แท็กข้อความที่ซ่อนอยู่แทนที่จะใช้แท็กอินพุตที่ซ่อนอยู่ <input type = "text" value = "0" id = 'txt' name = 'txt' style = "display: none" />
sajith

2
สิ่งนี้ได้ผลดีสำหรับฉัน ฉันแน่ใจว่ามันมีสถานการณ์เมื่อมันพัง แต่ทุกวิธีจะแก้ปัญหานี้ได้
Joren

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

55

นี่คือวิธีแก้ปัญหาเก่า ๆ ที่ง่ายมากสำหรับปัญหานี้

if (window.performance && window.performance.navigation.type === window.performance.navigation.TYPE_BACK_FORWARD) {
    alert('Got here using the browser "Back" or "Forward" button.');
}

window.performance ได้รับการสนับสนุนโดยเบราว์เซอร์หลักทั้งหมด


ฉันไม่เคยได้ยินเรื่องนี้ ฉันเพิ่งพบเอกสารนี้ ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation ) และสนใจที่จะฟังคุณอธิบายอย่างละเอียด (เช่นทำไมต้องใช้window.performance && window.performance.navigation.typeแทนที่จะเป็นเพียงแค่window.performance.navigation.TYPE_BACK_FORWARD?)
Ryan

5
window.performance.navigation.TYPE_BACK_FORWARDเป็นค่าคงที่ซึ่งเท่ากับ 2 เสมอดังนั้นจึงใช้เพื่อการเปรียบเทียบ
Bassem

1
ดูเหมือนว่าperformance.navigationจะเลิกใช้งานแล้วและขอแนะนำให้ใช้developer.mozilla.org/en-US/docs/Web/API/…
RubberDuckRabbit

1
นี้จะผิดพลาดสคริปต์ของคุณใน Safari - ทั้ง Mac และโทรศัพท์มือถือ
คริส Moschini

1
Firefox v70 จะรองรับ performance.navigation = 2สำหรับปุ่มย้อนกลับ จนกระทั่ง v70 1ก็กลับมาอย่างไม่ถูกต้อง
Andy Mercer

13

บทความนี้จะอธิบาย ดูโค้ดด้านล่าง: http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/

<html>
    <head>
        <script>

            function pageShown(evt){
                if (evt.persisted) {
                    alert("pageshow event handler called.  The page was just restored from the Page Cache (eg. From the Back button.");
                } else {
                    alert("pageshow event handler called for the initial load.  This is the same as the load event.");
                }
            }

            function pageHidden(evt){
                if (evt.persisted) {
                    alert("pagehide event handler called.  The page was suspended and placed into the Page Cache.");
                } else {
                    alert("pagehide event handler called for page destruction.  This is the same as the unload event.");
                }
            }

            window.addEventListener("pageshow", pageShown, false);
            window.addEventListener("pagehide", pageHidden, false);

        </script>
    </head>
    <body>
        <a href="http://www.webkit.org/">Click for WebKit</a>
    </body>
</html>

1
นี่เป็นคำตอบที่ดีใช้ได้กับ Chrome 40 / Firefox 35 เวอร์ชันล่าสุดแม้ว่า IE11 จะไม่รองรับเหตุการณ์เหล่านั้น
Slava Abakumov

อ้างอิงจากcaniuse.com/#feat=page-transition-eventsเหตุการณ์การเปลี่ยนหน้าได้รับการสนับสนุนจริงใน IE11 + ตามที่เราพูดมีการครอบคลุมคุณลักษณะทั่วโลก 88%
Cristian

FYI, Chrome จะส่งกลับevent.persisted= falseแม้ว่าจะกดปุ่มย้อนกลับก็ตาม คุณต้องใช้window.performance.navigationหรือ PerformanceNavigationTiming สำหรับ Chrome
Andy Mercer

4

สำหรับเบราว์เซอร์สมัยใหม่สิ่งนี้ดูเหมือนจะเป็นวิธีที่ถูกต้องแล้ว:

const perfEntries = performance.getEntriesByType('navigation');
if (perfEntries.length && perfEntries[0].type === 'back_forward') {
  console.log('User got here from Back or Forward button.');
}

สิ่งนี้ยังคงเป็นแบบ "ทดลอง" ณ มกราคม 2020 แต่ดูเหมือนว่าจะได้รับการสนับสนุนอย่างดี

https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming


1
ดีกว่าที่จะใช้ === แทน ==
Aboozar Krabi

3

คุณสามารถแก้ได้โดยใช้เหตุการณ์onbeforeunload :

window.onbeforeunload = function () { }

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

นี่คือตัวอย่างโค้ดแบบเต็ม:

<html>
<head>
<title>onbeforeunload.html</title>
<script>
window.onbeforeunload = function () { }

function myfun()
{
   alert("The page has been refreshed.");
}
</script>

<body onload="myfun()">

Hello World!<br>

</body>
</html>

ลองใช้ออกจากหน้านี้จากนั้นกลับโดยใช้ปุ่ม "ย้อนกลับ" หรือ "ไปข้างหน้า" ในเบราว์เซอร์ของคุณ

ทำงานได้ดีใน IE, FF และ Chrome

แน่นอนคุณสามารถทำอะไรก็ได้ที่คุณต้องการในฟังก์ชันmyfun

ข้อมูลเพิ่มเติม: http://www.hunlock.com/blogs/Mastering_The_Back_Button_With_Javascript


ใช้งานได้ใน Safari สำหรับฉัน
Jakob

2

ดังที่ได้กล่าวไว้ข้างต้นฉันพบวิธีแก้ปัญหาแล้วและกำลังโพสต์ไว้ที่นี่เพื่ออ้างอิงและแสดงความคิดเห็น

ขั้นตอนแรกของการแก้ปัญหาคือการเพิ่มสิ่งต่อไปนี้ในหน้า:

<!-- at the top of the content page -->
<IFRAME id="page_is_fresh" src="fresh.html" style="display:none;"></IFRAME>
<SCRIPT style="text/javascript">
  function reload_stale_page() { location.reload(); }
</SCRIPT>

เนื้อหาของfresh.htmlไม่สำคัญดังนั้นสิ่งต่อไปนี้ควรเพียงพอ:

<!-- fresh.html -->
<HTML><BODY></BODY></HTML>

เมื่อโค้ดฝั่งไคลเอ็นต์อัปเดตเพจจำเป็นต้องตั้งค่าสถานะการแก้ไขดังนี้:

function trigger_reload_if_user_clicks_back_button()
{
  // "dis-arm" the reload stale page function so it doesn't fire  
  // until the page is reloaded from the browser's cache
  window.reload_stale_page = function(){};

  // change the IFRAME to point to a page that will reload the 
  // page when it loads
  document.getElementById("page_is_fresh").src = "stale.html";
}

stale.htmlทำงานทั้งหมด: เมื่อโหลดแล้วจะเรียกใช้reload_stale_pageฟังก์ชันซึ่งจะรีเฟรชหน้าหากจำเป็น ครั้งแรกที่โหลด (กล่าวคือหลังจากทำการแก้ไขแล้วreload_stale_pageฟังก์ชันจะไม่ทำอะไรเลย)

<!-- stale.html -->
<HTML><BODY>
<SCRIPT type="text/javascript">window.parent.reload_stale_page();</SCRIPT>
</BODY></HTML>

จากการทดสอบ (ขั้นต่ำ) ของฉันในขั้นตอนนี้ดูเหมือนว่าจะได้ผลตามที่ต้องการ ฉันมองข้ามอะไรไปหรือเปล่า?


ไม่ใช่ว่าฉันรู้ แต่ยังไม่ได้ทดสอบอย่างเต็มที่ getElementById ไม่รองรับเบราว์เซอร์รุ่นเก่าบางรุ่น แต่สามารถเปลี่ยนเป็น jquery หรือบางอย่างได้ง่ายหากจำเป็น
ทอม

2

คุณสามารถใช้ localStorage หรือ sessionStorage ( http://www.w3schools.com/html/html5_webstorage.asp ) เพื่อตั้งค่าสถานะ (แทนที่จะใช้แบบฟอร์มที่ซ่อนอยู่)


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

1

การใช้หน้านี้โดยเฉพาะการผสมผสานความคิดเห็นโดย @sajith เกี่ยวกับคำตอบโดย @Nick White และหน้านี้: http://www.mrc-productivity.com/techblog/?p=1235

<form name="ignore_me" style="display:none">
    <input type="text" id="reloadValue" name="reloadValue" value="" />
</form>

$(function ()
{
    var date = new Date();
    var time = date.getTime();

    if ($("#reloadValue").val().length === 0)
    {
        $("#reloadValue").val(time);
    }
    else
    {
        $("#reloadValue").val("");
        window.location.reload();
    }
});

1

นี่คือเวอร์ชัน jQuery ฉันพบว่าจำเป็นต้องใช้มันสองสามครั้งเนื่องจากวิธีที่เดสก์ท็อป / มือถือ Safari จัดการแคชเมื่อผู้ใช้กดปุ่มย้อนกลับ

$(window).bind("pageshow", function(event) {
    if (event.originalEvent.persisted) {
        // Loading from cache
    }
});

1
ดูเหมือนจะไม่ทำงานใน Chrome เท่าที่ฉันสามารถบอกได้ console.log จะถูกทริกเกอร์ในคำสั่ง else เท่านั้น (เพิ่มสำหรับการทดสอบ) ไม่ว่าฉันจะเข้าถึงเพจอย่างไร
Luke

0

วันนี้ฉันพบปัญหาที่คล้ายกันและฉันแก้ไขด้วย localStorage (ที่นี่พร้อม jQuery เล็กน้อย):

$(function() {

    if ($('#page1').length) {
        // this code must only run on page 1

        var checkSteps = function () {
            if (localStorage.getItem('steps') == 'step2') {
                // if we are here, we know that:
                // 1. the user is on page 1
                // 2. he has been on page 2
                // 3. this function is running, which means the user has submitted the form
                // 4. but steps == step2, which is impossible if the user has *just* submitted the form
                // therefore we know that he has come back, probably using the back button of his browser
                alert('oh hey, welcome back!');
            } else {
                setTimeout(checkSteps, 100);
            }
        };

        $('#form').on('submit', function (e) {
            e.preventDefault();
            localStorage.setItem('steps', 'step1'); // if "step1", then we know the user has submitted the form
            checkOrderSteps();
            // ... then do what you need to submit the form and load page 2
        });
    }

    if ($('#page2').length) {
        // this code must only run on page 2
        localStorage.setItem('steps', 'step2');
    }

});

Si โดยพื้นฐาน:

ในหน้า 1 เมื่อผู้ใช้ส่งแบบฟอร์มเราตั้งค่า "ขั้นตอน" ใน localStorage เพื่อระบุขั้นตอนที่ผู้ใช้ดำเนินการ ในเวลาเดียวกันเราเปิดตัวฟังก์ชันที่มีการหมดเวลาซึ่งจะตรวจสอบว่าค่านี้มีการเปลี่ยนแปลงหรือไม่ (เช่น 10 ครั้ง / วินาที)

ในหน้าที่ 2 เราเปลี่ยนค่าดังกล่าวทันที

ดังนั้นหากผู้ใช้ใช้ปุ่มย้อนกลับและเบราว์เซอร์เรียกคืนหน้าที่ 1 ในสถานะเดิมเมื่อเราออกไปฟังก์ชัน checkSteps ยังคงทำงานอยู่และสามารถตรวจพบว่ามีการเปลี่ยนแปลงค่าใน localStorage (และสามารถดำเนินการที่เหมาะสมได้ ). เมื่อการตรวจสอบนี้บรรลุวัตถุประสงค์แล้วก็ไม่จำเป็นต้องเรียกใช้งานต่อดังนั้นเราจึงไม่ใช้ setTimeout อีกต่อไป

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