Làm cách nào để phát hiện xem người dùng có truy cập vào một trang bằng nút quay lại hay không?


90

Câu hỏi này tương tự như Theo dõi khi người dùng nhấn nút quay lại trên trình duyệt , nhưng không giống ... Tôi có một giải pháp và đang đăng lên đây để tham khảo và phản hồi. Nếu ai có bất kỳ lựa chọn tốt hơn, tôi tất cả các tai!

Tình hình là mình có trang bị "in place edit", la flickr. Tức là có một DIV "nhấp vào đây để thêm mô tả", khi nhấp vào sẽ biến thành một TEXTAREA với các nút Lưu và Hủy. Nhấp vào Lưu sẽ đăng dữ liệu lên máy chủ để cập nhật cơ sở dữ liệu và đặt mô tả mới vào DIV thay cho TEXTAREA. Nếu trang được làm mới, mô tả mới sẽ được hiển thị từ cơ sở dữ liệu với tùy chọn "nhấp để chỉnh sửa". Ngày nay, công cụ web 2.0 khá chuẩn.

Vấn đề là nếu:

  1. trang được tải mà không có mô tả
  2. một mô tả được thêm bởi người dùng
  3. trang được điều hướng khỏi bằng cách nhấp vào liên kết
  4. người dùng nhấp vào nút quay lại

Sau đó, những gì được hiển thị (từ bộ nhớ cache của trình duyệt) là phiên bản của trang không có DIV được sửa đổi động có chứa mô tả mới.

Đây là một vấn đề khá lớn vì người dùng cho rằng bản cập nhật của họ đã bị mất và không nhất thiết phải hiểu rằng họ cần phải làm mới trang để xem các thay đổi.

Vì vậy, câu hỏi đặt ra là: Làm thế nào bạn có thể gắn cờ một trang là đang được sửa đổi sau khi nó tải xong, và sau đó phát hiện khi nào người dùng "quay lại trang đó" và buộc làm mới trong tình huống đó?


Điều này khác với câu hỏi mà bạn đã trích dẫn như thế nào?
innaM

câu hỏi tương tự, nhưng tôi nghĩ rằng môi trường và do đó câu trả lời là khác nhau, tôi có thể sai. giải thích của tôi về những gì một vấn đề có thể được giải quyết với giải pháp khác là: người dùng nhấp vào một tab trên trang được tải bởi ajax, sau đó nhấp vào tab khác, v.v. nhấp vào nút quay lại sẽ đưa bạn trở lại một trang khác, không phải tab trước đó. họ muốn quay lại "lịch sử ajax" trong "lịch sử trang". ít nhất đó là ấn tượng của tôi về những gì Trình quản lý lịch sử trình duyệt Yahoo phải làm. tôi đã theo đuổi một cái gì đó cơ bản hơn một chút.
Tom

Câu trả lời được chấp nhận có tính năng lừa iframe của bạn.
innaM

Câu trả lời:


79

Sử dụng một hình thức ẩn. Dữ liệu biểu mẫu được giữ nguyên (thường là) trong các trình duyệt khi bạn tải lại hoặc nhấn nút quay lại để quay lại trang. Những điều sau đây nằm trong trang của bạn (có thể ở gần cuối trang):

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

Trong javascript của bạn, bạn sẽ cần những thứ sau:

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

Các js đánh dấu biểu mẫu phải thực thi sau khi html được phân tích cú pháp hoàn toàn, nhưng bạn có thể đặt cả biểu mẫu và js nội dòng ở đầu trang (js thứ hai) nếu độ trễ của người dùng là mối quan tâm nghiêm trọng.


5
"Dữ liệu biểu mẫu được bảo toàn (thường) trong trình duyệt" - bạn có thể mở rộng về điều đó không? nó không được bảo tồn trong một số trình duyệt? hoặc trong một số tình huống?
Tom,

4
Trên thực tế, hãy để tôi liệt kê tất cả những cách tôi có thể nghĩ về điều này là sai. (1) Opera giữ trạng thái đầy đủ của trang và sẽ không thực thi lại js. (2) Nếu cài đặt bộ nhớ cache của bạn được tinh chỉnh để buộc trang tải từ máy chủ trên nút quay lại, dữ liệu biểu mẫu có thể bị mất, điều này tốt cho mục đích của câu hỏi này. (3) Các trình duyệt trên điện thoại có bộ nhớ cache nhỏ hơn nhiều và trình duyệt có thể đã xóa trang khỏi bộ nhớ cache (không phải là vấn đề cho những mục đích này).
Nick White

10
Trong một số trình duyệt, các thẻ ẩn không được giữ nguyên. Vì vậy, bạn có thể sử dụng thẻ văn bản ẩn thay vì sử dụng thẻ nhập ẩn. <input type = "text" value = "0" id = 'txt' name = 'txt' style = "display: none" />
sajith 18/01/12

2
Nó hiệu quả tuyệt vời đối với tôi. Tôi chắc chắn rằng nó có những tình huống khi nó bị hỏng, nhưng mọi giải pháp đều phù hợp với vấn đề này.
Joren

Nó không hoạt động trên iPhone với trình duyệt Safari, hãy thử nó, khi bạn bấm vào nút quay lại, js không được gọi lại.
woheras

52

Đây là một giải pháp hiện đại rất dễ dàng cho vấn đề cũ này.

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 hiện được hỗ trợ bởi tất cả các trình duyệt chính.


Tôi đã không nghe nói về điều này. Tôi vừa tìm thấy tài liệu này ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation ) và muốn nghe bạn giải thích (ví dụ: tại sao cần window.performance && window.performance.navigation.typethay vì chỉ window.performance.navigation.TYPE_BACK_FORWARD?).
Ryan

5
window.performance.navigation.TYPE_BACK_FORWARDlà hằng số luôn bằng 2. Vì vậy nó chỉ được dùng để so sánh.
Bassem

Performance.navigation được hỗ trợ ở tất cả các thiết bị ngoại trừ andorid & opera mini nhưng không có vấn đề gì, nó rất đẹp ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation )
Elbaz ngày

1
Có vẻ như performance.navigationkhông được dùng nữa và thay vào đó, bạn nên sử dụng developer.mozilla.org/en-US/docs/Web/API/…
RubberDuckRabbit.

1
Firefox v70 sẽ hỗ trợ performance.navigation = 2cho các lần truy cập nút quay lại. Cho đến v70, nó trả về không chính xác 1.
Andy Mercer,

13

Bài báo này giải thích nó. Xem mã bên dưới: 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
Đây là một câu trả lời hay, hoạt động trong Chrome 40 / Firefox 35. IE11 mới nhất, tuy nhiên, IE11 không hỗ trợ các sự kiện đó.
Slava Abakumov

Theo caniuse.com/#feat=page-transition-events, các sự kiện chuyển đổi trang thực sự được hỗ trợ trong IE11 + Như chúng tôi đã nói, có 88% phạm vi toàn cầu của tính năng
Cristian,

FYI, Chrome trả về event.persisted= false, ngay cả khi nhấn từ nút quay lại. Bạn phải sử dụng window.performance.navigationhoặc PerformanceNavigationTiming cho Chrome.
Andy Mercer,

4

Đối với các trình duyệt hiện đại, đây có vẻ là cách phù hợp hiện nay:

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

Đây vẫn là "Thử nghiệm" kể từ tháng 1 năm 2020, nhưng dường như đã được hỗ trợ tốt.

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


1
tốt hơn nên sử dụng === thay vì ==
Aboozar Rajabi

2

Như đã đề cập ở trên, tôi đã tìm ra giải pháp và đang đăng nó lên đây để tham khảo và phản hồi.

Giai đoạn đầu tiên của giải pháp là thêm phần sau vào trang:

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

Nội dung của fresh.htmlkhông quan trọng, vì vậy những điều sau đây cần đủ:

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

Khi mã phía máy khách cập nhật trang, nó cần gắn cờ sửa đổi như sau:

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.htmlthực hiện tất cả công việc: Khi nó được tải, nó sẽ gọi reload_stale_pagehàm sẽ làm mới trang nếu cần. Lần đầu tiên nó được tải (tức là sau khi sửa đổi được thực hiện, reload_stale_pagehàm sẽ không hoạt động gì cả.)

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

Từ thử nghiệm (tối thiểu) của tôi ở giai đoạn này, điều này dường như hoạt động như mong muốn. Tôi đã bỏ qua bất cứ điều gì?


Không phải tôi biết, nhưng tôi đã không thử nghiệm nó đầy đủ. getElementById không được hỗ trợ trong một số trình duyệt cũ hơn, nhưng điều đó dễ dàng hoán đổi cho jquery hoặc thứ gì đó nếu cần.
Tom

2

Bạn có thể giải quyết nó bằng cách sử dụng sự kiện onbeforeunload :

window.onbeforeunload = function () { }

Có chức năng quản lý sự kiện trống onbeforeunload có nghĩa là trang sẽ được xây dựng lại mỗi khi nó được truy cập. Javascrip sẽ chạy lại, các tập lệnh phía máy chủ sẽ được chạy lại, trang sẽ được xây dựng như thể người dùng chạm vào nó lần đầu tiên, ngay cả khi người dùng truy cập trang chỉ bằng cách nhấn nút quay lại hoặc chuyển tiếp .

Đây là mã đầy đủ của một ví dụ:

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

Hãy thử, điều hướng khỏi trang này và sau đó quay lại bằng cách sử dụng nút "Quay lại" hoặc "Chuyển tiếp" trong trình duyệt của bạn.

Nó hoạt động tốt trên IE, FF và Chrome.

Tất nhiên bạn có thể làm bất cứ điều gì bạn muốn bên trong hàm myfun .

Thông tin thêm: http://www.hunlock.com/blogs/Mastering_The_Back_Button_With_Javascript


Làm việc trong Safari cho tôi
Jakob

2

Bạn có thể sử dụng localStorage hoặc sessionStorage ( http://www.w3schools.com/html/html5_webstorage.asp ) để đặt cờ (thay vì sử dụng biểu mẫu ẩn).


Cách giải quyết tốt đẹp của nó nhưng làm thế nào để bạn nó nếu anh muốn phát hiện này mỗi lần, khi tôi mở trang web và đóng nó, tôi cần phải phát hiện chỉ khi tôi mở ra và quay trở lại trước khi đóng cửa
Elbaz

1

Sử dụng trang này, đặc biệt kết hợp bình luận của @sajith về câu trả lời của @Nick White và trang này: 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

Đây là một phiên bản jQuery. Tôi đã gặp phải tình trạng cần sử dụng nó một vài lần do cách máy tính để bàn / di động Safari xử lý bộ nhớ cache khi người dùng nhấn nút quay lại.

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

Có vẻ như không hoạt động trong Chrome theo như tôi có thể nói. Console.log chỉ được kích hoạt trong câu lệnh else (được thêm vào để thử nghiệm) bất kể cách tôi truy cập trang.
Luke

0

Hôm nay tôi gặp phải sự cố tương tự và tôi đã giải quyết nó bằng localStorage (ở đây với một chút 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 về cơ bản:

Trên trang 1, khi người dùng gửi biểu mẫu, chúng tôi đặt giá trị "các bước" trong localStorage để cho biết người dùng đã thực hiện bước nào. Đồng thời, chúng tôi khởi chạy một hàm có thời gian chờ sẽ kiểm tra xem giá trị này có bị thay đổi hay không (ví dụ: 10 lần / giây).

Ở trang 2, chúng tôi ngay lập tức thay đổi giá trị đã nói.

Vì vậy, nếu người dùng sử dụng nút quay lại và trình duyệt khôi phục trang 1 ở trạng thái chính xác như khi chúng ta rời khỏi nó, thì chức năng checkSteps vẫn đang chạy và có thể phát hiện rằng giá trị trong localStorage đã bị thay đổi (và có thể thực hiện hành động thích hợp ). Khi kiểm tra này đã hoàn thành mục đích của nó, không cần phải tiếp tục chạy nó, vì vậy chúng tôi chỉ cần không sử dụng setTimeout nữa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.