Bagaimana cara mendeteksi jika pengguna telah sampai ke halaman menggunakan tombol kembali?

90

Pertanyaan ini mirip dengan Lacak saat pengguna menekan tombol kembali di browser , tetapi tidak sama ... Saya punya solusi dan saya mempostingnya di sini untuk referensi dan umpan balik. Jika ada yang punya pilihan yang lebih baik, saya mendengarkan!

Situasinya adalah saya memiliki halaman dengan "edit di tempat", a la flickr. Yaitu ada DIV "klik di sini untuk menambahkan deskripsi", yang bila diklik berubah menjadi TEXTAREA dengan tombol Simpan dan Batal. Mengklik Simpan posting data ke server untuk memperbarui database dan menempatkan deskripsi baru di DIV sebagai pengganti TEXTAREA. Jika halaman di-refresh, deskripsi baru ditampilkan dari database dengan opsi "klik untuk mengedit". Hal-hal web 2.0 yang cukup standar hari ini.

Masalahnya adalah jika:

  1. halaman dimuat tanpa deskripsi
  2. deskripsi ditambahkan oleh pengguna
  3. halaman dinavigasi keluar dengan mengklik link
  4. pengguna mengklik tombol kembali

Kemudian yang ditampilkan (dari cache browser) adalah versi halaman tanpa DIV yang dimodifikasi secara dinamis berisi deskripsi baru.

Ini adalah masalah yang cukup besar karena pengguna berasumsi bahwa pembaruan mereka telah hilang dan tidak perlu memahami bahwa mereka perlu menyegarkan laman untuk melihat perubahan.

Jadi, pertanyaannya adalah: Bagaimana Anda bisa menandai halaman sebagai diubah setelah dimuat, dan kemudian mendeteksi ketika pengguna "kembali ke sana" dan memaksa penyegaran dalam situasi itu?

Tom
sumber
Apa bedanya dengan pertanyaan yang Anda kutip?
innaM
pertanyaannya serupa, tetapi saya pikir lingkungan dan karenanya jawabannya berbeda, saya bisa saja salah. interpretasi saya tentang masalah apa yang mungkin bisa diselesaikan dengan solusi lain adalah: pengguna mengklik tab pada halaman yang dimuat oleh ajax, lalu tab lain, dan seterusnya. mengklik tombol kembali akan membawa Anda kembali ke halaman lain, bukan tab sebelumnya. mereka ingin memutar kembali melalui "riwayat ajax" dalam "riwayat halaman". setidaknya itulah kesan saya tentang apa yang seharusnya dilakukan oleh Yahoo Browser History Manager. Saya mencari sesuatu yang sedikit lebih mendasar.
Tom
Jawaban yang diterima menampilkan trik iframe Anda.
innaM

Jawaban:

79

Gunakan formulir tersembunyi. Data formulir disimpan (biasanya) di browser saat Anda memuat ulang atau menekan tombol kembali untuk kembali ke halaman. Hal berikut masuk ke halaman Anda (mungkin di dekat bagian bawah):

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

Di javascript Anda, Anda memerlukan yang berikut ini:

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 yang mengendus formulir harus dieksekusi setelah html sepenuhnya diurai, tetapi Anda dapat meletakkan formulir dan js sebaris di bagian atas halaman (js detik) jika latensi pengguna menjadi masalah serius.

Nick White
sumber
5
"Data formulir disimpan (biasanya) di browser" - apakah Anda dapat mengembangkannya? apakah itu tidak disimpan di beberapa browser? atau dalam beberapa situasi?
Tom
4
Sebenarnya, izinkan saya mendaftar semua hal yang menurut saya bisa salah. (1) Opera mempertahankan status penuh halaman dan tidak akan mengeksekusi ulang js. (2) Jika pengaturan cache Anda di-tweak untuk memaksa halaman memuat dari server dengan tombol kembali, data formulir mungkin hilang, yang bagus untuk keperluan pertanyaan ini. (3) Browser telepon memiliki cache yang jauh lebih kecil dan browser mungkin telah menghapus halaman dari cache (bukan masalah untuk tujuan ini).
Nick White
10
Di beberapa browser, tag tersembunyi tidak dipertahankan. Jadi Anda bisa menggunakan tag teks tersembunyi daripada menggunakan tag masukan tersembunyi. <input type = "text" value = "0" id = 'txt' name = 'txt' style = "display: none" />
sajith
2
Ini bekerja dengan baik untuk saya. Saya yakin ada situasi ketika rusak, tetapi setiap solusi akan untuk masalah ini.
Joren
Ini tidak berfungsi di iPhone dengan browser Safari, coba, ketika Anda mengklik tombol kembali, js tidak dipanggil lagi.
woheras
53

Berikut adalah solusi modern yang sangat mudah untuk masalah lama ini.

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 saat ini didukung oleh semua browser utama.

Bassem
sumber
Saya belum pernah mendengar tentang ini. Saya baru saja menemukan dokumentasi ini ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation ) dan akan tertarik untuk mendengar penjelasan Anda (misalnya, mengapa perlu window.performance && window.performance.navigation.typealih - alih hanya window.performance.navigation.TYPE_BACK_FORWARD?).
Ryan
5
window.performance.navigation.TYPE_BACK_FORWARDadalah konstanta yang selalu sama dengan 2. Jadi, ini hanya digunakan untuk perbandingan.
Bassem
Performance.navigation didukung di semua perangkat kecuali andorid & opera mini tetapi tidak ada masalah, ini sangat bagus ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation )
Elbaz
1
Sepertinya performance.navigationsudah usang dan disarankan untuk menggunakan developer.mozilla.org/en-US/docs/Web/API/…
RubberDuckRabbit
1
Firefox v70 akan mendukung performance.navigation = 2untuk klik tombol kembali. Hingga v70, kesalahan dikembalikan 1.
Andy Mercer
13

Artikel ini menjelaskannya. Lihat kode di bawah ini: 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>
Drew Baker
sumber
1
Ini adalah jawaban yang bagus, berfungsi di Chrome 40 / Firefox 35 terbaru. IE11 tidak mendukung acara tersebut.
Slava Abakumov
Menurut caniuse.com/#feat=page-transition-events, peristiwa transisi halaman sebenarnya didukung di IE11 + Seperti yang kita bicarakan, ada 88% cakupan global dari fitur tersebut
Cristian
FYI, Chrome mengembalikan event.persisted= false, bahkan saat menekan dari tombol kembali. Anda harus menggunakan window.performance.navigationatau PerformanceNavigationTiming untuk Chrome.
Andy Mercer
4

Untuk peramban modern, ini sepertinya cara yang benar sekarang:

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

Ini masih "Eksperimental" pada Jan 2020, tetapi tampaknya didukung dengan baik.

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

getup8
sumber
1
lebih baik menggunakan === daripada ==
Aboozar Rajabi
2

Seperti disebutkan di atas, saya telah menemukan solusi dan mempostingnya di sini untuk referensi dan umpan balik.

Langkah pertama dari solusi adalah menambahkan yang berikut ini ke halaman:

<!-- 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>

Isi dari fresh.htmltidak penting, jadi berikut ini sudah cukup:

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

Ketika kode sisi klien memperbarui halaman, itu perlu menandai modifikasi sebagai berikut:

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.htmlmelakukan semua pekerjaan: Saat dimuat itu akan memanggil reload_stale_pagefungsi yang akan menyegarkan halaman jika perlu. Pertama kali dimuat (yaitu setelah modifikasi dilakukan, reload_stale_pagefungsi tidak akan melakukan apa pun.)

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

Dari pengujian (minimal) saya pada tahap ini, ini sepertinya berfungsi seperti yang diinginkan. Apakah saya melewatkan sesuatu?

Tom
sumber
Setahu saya belum, tapi saya belum mengujinya sepenuhnya. getElementById tidak didukung di beberapa browser lama, tapi itu mudah ditukar dengan jquery atau sesuatu jika diperlukan.
Tom
2

Anda dapat menyelesaikannya menggunakan acara onbeforeunload :

window.onbeforeunload = function () { }

Memiliki fungsi event manager kosong onbeforeunload berarti halaman akan dibangun kembali setiap kali diakses. Javascript akan dijalankan ulang, skrip sisi server akan dijalankan kembali, halaman akan dibuat seolah-olah pengguna pertama kali membukanya, meskipun pengguna membuka halaman hanya dengan menekan tombol kembali atau maju .

Berikut adalah kode lengkap dari sebuah contoh:

<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>

Cobalah, keluar dari halaman ini lalu kembali menggunakan tombol "Kembali" atau "Maju" di browser Anda.

Ini berfungsi dengan baik di IE, FF dan Chrome.

Tentu saja Anda dapat melakukan apapun yang Anda inginkan di dalam fungsi myfun .

Info lebih lanjut: http://www.hunlock.com/blogs/Mastering_The_Back_Button_With_Javascript

Nes
sumber
Bekerja di Safari untuk saya
Jakob
2

Anda dapat menggunakan localStorage atau sessionStorage ( http://www.w3schools.com/html/html5_webstorage.asp ) untuk mengatur bendera (daripada menggunakan formulir tersembunyi).

rerezz
sumber
itu solusi yang bagus tetapi bagaimana Anda melakukannya jika dia ingin mendeteksi ini setiap saat, ketika saya membuka situs dan menutupnya, saya perlu mendeteksi tepat ketika saya membuka dan kembali sebelum menutup
Elbaz
1

Menggunakan halaman ini, terutama menggabungkan komentar oleh @sajith tentang jawaban oleh @Nick White dan halaman ini: 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();
    }
});
nmit026
sumber
1

Ini versi jQuery. Saya mengalami keharusan untuk menggunakannya beberapa kali karena cara Safari desktop / seluler menangani cache saat pengguna menekan tombol kembali.

$(window).bind("pageshow", function(event) {
    if (event.originalEvent.persisted) {
        // Loading from cache
    }
});
Wes
sumber
Sejauh yang saya tahu, tampaknya tidak berfungsi di Chrome. Console.log hanya dipicu di pernyataan lain (ditambahkan untuk pengujian) terlepas dari bagaimana saya mengakses halaman.
Lukas
0

Saya mengalami masalah serupa hari ini dan saya menyelesaikannya dengan localStorage (di sini dengan sedikit 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 pada dasarnya:

Pada halaman 1, saat pengguna mengirimkan formulir, kami menetapkan nilai "langkah" di localStorage untuk menunjukkan langkah apa yang telah diambil pengguna. Pada saat yang sama, kami meluncurkan fungsi dengan waktu tunggu yang akan memeriksa apakah nilai ini telah diubah (misalnya 10 kali / detik).

Pada halaman 2, kami segera mengubah nilai tersebut.

Jadi jika pengguna menggunakan tombol kembali dan browser mengembalikan halaman 1 dalam keadaan yang sama persis seperti ketika kita meninggalkannya, fungsi checkSteps masih berjalan, dan dapat mendeteksi bahwa nilai di localStorage telah diubah (dan dapat mengambil tindakan yang sesuai. ). Setelah pemeriksaan ini memenuhi tujuannya, tidak perlu terus menjalankannya, jadi kami tidak lagi menggunakan setTimeout.

s427
sumber