Biến cố định giữa các lần tải trang


95

Tôi đang cố gắng chụp nút gửi biểu mẫu của mình và nếu biểu mẫu được gửi, trang sẽ làm mới và tôi hiển thị một vài trường ẩn. Tôi muốn biết liệu biểu mẫu đã được gửi trước đó hay chưa và nếu nó được gửi khi tải lại, tôi muốn hiện các trường ẩn. Tôi đã cố gắng sử dụng một biến toàn cục để đạt được điều này, tuy nhiên tôi không thể làm cho nó hoạt động bình thường.

Đây là những gì tôi đã thử:

  var clicked = false;

  $(document).ready(function() {

    $("input[type='submit'][value='Search']").attr("onclick", "form.act.value='detailSearch'; clicked = true;  return true;");

    if (clicked == true) {
      // show hidden fields
    } else {
      // don't show hidden fields
    }
  });

Bất kỳ đề xuất về những gì là sai với mã này?


1
Tôi không nghĩ rằng điều này có thể được thực hiện mà không có một số loại lưu trữ. Tất cả các biến JS của bạn sẽ được xóa sạch. Toàn bộ phạm vi của bạn sẽ được tái chế.
Dave Alperovich

Tại sao bạn không đặt hầu hết trang của mình thành "một phần" và làm mới phần đó?
Dave Alperovich

Một phần là gì? Xin lỗi tôi không biết về điều đó.
Neophile

Bạn đã cân nhắc gửi biểu mẫu qua ajax và hiển thị các trường sau khi gửi chưa?
dannyshaw

1
Bạn có thể giải thích tại sao bạn cần làm mới trang không? Nếu chúng tôi có thể tránh nó, bạn có thể làm những gì bạn muốn nếu bạn chỉ preventDefaulttham gia submitsự kiện (thay vì clickbạn đang sử dụng.)
Peleg

Câu trả lời:


202

Vì HTTP là không trạng thái, mỗi khi bạn tải trang, nó sẽ sử dụng các giá trị ban đầu của bất kỳ thứ gì bạn đặt trong JavaScript. Bạn không thể đặt một biến toàn cục trong JS và chỉ cần đặt giá trị đó sau khi tải lại trang.

Có một số cách bạn có thể lưu trữ giá trị ở một nơi khác để bạn có thể khởi tạo nó khi tải bằng JavaScript


Chuỗi truy vấn

Khi gửi biểu mẫu bằng GETphương thức này, url sẽ được cập nhật bằng một chuỗi truy vấn ( ?parameter=value&something=42). Bạn có thể sử dụng điều này bằng cách đặt trường đầu vào trong biểu mẫu thành một giá trị nhất định. Đây sẽ là ví dụ đơn giản nhất:

<form method="GET">
    <input type="hidden" name="clicked" value="true" />
    <input type="submit" />
</form>

Khi tải trang đầu tiên, không có chuỗi truy vấn nào được đặt. Khi bạn gửi biểu mẫu này, namevaluekết hợp của đầu vào được chuyển vào chuỗi truy vấn dưới dạng clicked=true. Vì vậy, khi trang tải lại với chuỗi truy vấn đó, bạn có thể kiểm tra xem nút đã được nhấp chưa.

Để đọc dữ liệu này, bạn có thể sử dụng tập lệnh sau khi tải trang:

function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

var clicked = getParameterByName('clicked');

( Nguồn )

Khả năng sử dụng điều này phụ thuộc vào cách biểu mẫu của bạn hiện đang hoạt động, nếu bạn đã sử dụng POST thì điều này có thể có vấn đề.

Ngoài ra, đối với các tập dữ liệu lớn hơn, điều này không tối ưu. Chuyển xung quanh một chuỗi không phải là một vấn đề lớn nhưng đối với các mảng và đối tượng dữ liệu, bạn có thể nên sử dụng Web Storage hoặc cookie. Mặc dù các chi tiết khác nhau một chút giữa các trình duyệt, giới hạn thực tế đối với độ dài URI là khoảng 2000 ký tự


Lưu trữ web

Với sự ra đời của HTML5, chúng tôi cũng có Web Storage, cho phép bạn lưu thông tin trong trình duyệt khi tải trang. Có localStoragethể lưu dữ liệu trong một thời gian dài hơn (miễn là người dùng không xóa nó theo cách thủ công) và sessionStoragechỉ lưu dữ liệu trong phiên duyệt hiện tại của bạn. Cái sau rất hữu ích cho bạn ở đây, vì bạn không muốn đặt "đã nhấp" thành true khi người dùng quay lại sau.

Ở đây tôi đặt bộ nhớ cho sự kiện nhấp vào nút, nhưng bạn cũng có thể liên kết nó với biểu mẫu gửi hoặc bất kỳ thứ gì khác.

$('input[type="submit"][value="Search"]').click(function() {
    sessionStorage.setItem('clicked', 'true');
});

Sau đó, khi bạn tải trang, bạn có thể kiểm tra xem nó đã được đặt chưa bằng cách sử dụng:

var clicked = sessionStorage.getItem('clicked');

Mặc dù giá trị này chỉ được lưu trong phiên duyệt web này, nhưng có thể bạn muốn đặt lại nó sớm hơn. Để làm như vậy, hãy sử dụng:

sessionStorage.removeItem('clicked');

Nếu bạn muốn lưu một đối tượng hoặc mảng JS, bạn nên chuyển đổi nó thành một chuỗi. Theo thông số kỹ thuật, có thể lưu các kiểu dữ liệu khác, nhưng điều này chưa được triển khai chính xác trên các trình duyệt.

//set
localStorage.setItem('myObject', JSON.stringify(myObject));

//get
var myObject = JSON.parse(localStorage.getItem('myObject'));

Hỗ trợ trình duyệt khá tuyệt vời vì vậy bạn nên yên tâm sử dụng tính năng này trừ khi bạn cần hỗ trợ các trình duyệt thực sự cũ / khó hiểu. Lưu trữ web là tương lai.


Bánh quy

Một giải pháp thay thế cho Lưu trữ web là lưu dữ liệu trong cookie. Cookie chủ yếu được tạo ra để đọc dữ liệu phía máy chủ, nhưng cũng có thể được sử dụng cho dữ liệu hoàn toàn phía máy khách.

Bạn đã sử dụng jQuery, điều này làm cho việc đặt cookie khá dễ dàng. Một lần nữa, tôi sử dụng clicksự kiện ở đây nhưng có thể được sử dụng ở bất cứ đâu.

$('input[type="submit"][value="Search"]').click(function() {
    $.cookie('clicked', 'true', {expires: 1}); // expires in 1 day
});

Sau đó, khi tải trang, bạn có thể đọc cookie như sau:

var clicked = $.cookie('clicked');

Vì cookie vẫn tồn tại qua các phiên trong trường hợp của bạn, bạn sẽ cần phải hủy đặt chúng ngay sau khi bạn làm bất cứ điều gì bạn cần làm với nó. Bạn sẽ không muốn người dùng quay lại một ngày sau đó và vẫn clickedđặt thành true.

if(clicked === "true") {
    //doYourStuff();
    $.cookie('clicked', null);
}

(có thể tìm thấy một cách không phải jQuery để đặt / đọc cookie tại đây )

Cá nhân tôi sẽ không sử dụng cookie cho một cái gì đó đơn giản như ghi nhớ trạng thái được nhấp, nhưng nếu chuỗi truy vấn không phải là một tùy chọn và bạn cần hỗ trợ các trình duyệt thực sự cũ không hỗ trợ sessionStorage thì điều này sẽ hoạt động. Bạn nên thực hiện điều đó bằng cách kiểm tra sessionStorage trước và chỉ khi điều đó không thành công, hãy sử dụng phương pháp cookie.


window.name

Mặc dù đối với tôi đây có vẻ giống như một vụ hack có thể bắt nguồn từ trước localStorage / sessionStorage, nhưng bạn có thể lưu trữ thông tin trong thuộc window.nametính:

window.name = "my value"

Nó chỉ có thể lưu trữ các chuỗi, vì vậy nếu bạn muốn lưu một đối tượng, bạn sẽ phải xâu chuỗi nó giống như localStorageví dụ trên :

window.name = JSON.stringify({ clicked: true });

Sự khác biệt chính là thông tin này được giữ lại không chỉ trên các trang làm mới mà còn trên các miền khác nhau. Tuy nhiên, nó bị hạn chế đối với tab hiện tại bạn đang ở.

Điều này có nghĩa là bạn có thể lưu một số thông tin trên trang của mình và miễn là người dùng vẫn ở trong tab đó, bạn có thể truy cập thông tin tương tự ngay cả khi anh ta duyệt qua trang web khác và quay lại. Nói chung, tôi khuyên bạn không nên sử dụng điều này trừ khi bạn thực sự cần lưu trữ thông tin tên miền chéo trong một phiên duyệt web.


9
Rất tiếc, chỉ sau khi viết, tôi mới đọc được phần mô tả tiền thưởng của bạn có nội dung "không có cookie hoặc bộ nhớ cục bộ". Tôi sẽ giữ nguyên nhận xét này cho những người khác có thể cần nó, nhưng bạn sẽ chỉ cần sử dụng chuỗi truy vấn mà tôi đoán.
Stephan Muller

1
Về cơ bản, tôi đã sử dụng localStorage trong nhiều trường hợp cho ứng dụng web của mình và tôi muốn tránh sử dụng quá nhiều biến localStorage. Tuy nhiên, tôi thích ý tưởng loại bỏ mục localStorage khi tôi đã hoàn tất. Đó là điều mà tôi không nghĩ đến khi sử dụng biến localStorage của mình.
Neophile

3
Trong trường hợp yêu cầu bài đăng, bạn có thể sửa đổi thuộc tính hành động $ ("# formid"). Attr ("action", url + "& click = 1") và cũng có thể phát hiện GET hoặc POST từ $ ("# formid"). Attr ( "method") nhưng nó có thể không giải quyết được cách phát hiện vấn đề tải lại
Tero Tolonen

2
@TheNewbie Đã lâu tôi chưa viết câu trả lời này, nhưng tôi vừa thêm một tùy chọn mới ( window.name). Nó chỉ có thể làm chính xác những gì bạn cần mà không cần sử dụng cookie / localStorage.
Stephan Muller

1
Tôi muốn thêm rằng lưu trữ cục bộ và phiên cũng không hoàn toàn đáng tin cậy trên các trình duyệt mới hơn. Thông thường có một dự phòng cho window.name.
JavaScript

5

Hãy thử sử dụng $.holdReady(),history

function show() {
  return $("form input[type=hidden]")
          .replaceWith(function(i, el) {
            return "<input type=text>"
          });
}

$.holdReady(true);
    if (history.state !== null && history.state.clicked === true) {
       // show hidden fields
       // if `history.state.clicked === true` ,
       // replace `input type=hidden` with `input type=text`
       show();
       console.log(history);

    } else {
        // don't show hidden fields
        console.log(history);
    }
$.holdReady(false);

  $(document).ready(function() {

    $("input[type=submit][value=Search]")
    .on("click", function(e) {
        e.preventDefault();
        if (history.state === null) {
          // do stuff
          history.pushState({"clicked":true});
          // replace `input type=hidden` with `input type=text`
          show();
          console.log(history);
        } else {
          // do other stuff
        };
    });

  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="POST">
    <input type="text" name="name" value="" />
    <input type="submit" value="Search" />
    <input type="hidden" />
    <input type="hidden" />
</form>


1

Sử dụng localeStoragehoặc sessionStoragecó vẻ là đặt cược tốt nhất.

Ý định lưu clickedbiến trong phạm vi găng hãy lưu trữ nó theo cách này:

if(localeStorage.getItem("clicked") === null)
    localeStorage.setItem("clicked", "FALSE"); // for the first time

$(document).ready(function() {

    $("input[type='submit'][value='Search']").attr("onclick", "form.act.value='detailSearch';return true;");

    var clicked = localeStorage.getItem("clicked") == "FALSE" ? "TRUE" : "FALSE";

    localeStorage.setItem("clicked", clicked);

    if (clicked == "TRUE") {
      // show hidden fields
    } else {
      // don't show hidden fields
    }

});

Tôi đang có ý định không sử dụng localstorage hoặc sessionStorage.
Neophile

-5

Bạn có thể thử điều này:

 $("input[type='submit'][value='Search']").click(function(){
     form.act.value='detailSearch'; 
     clicked = true;  
     return true;
});

Khi trang tải lại, giá trị vẫn nhận được là false.
Neophile

1
@TheNewbie Bạn có nghĩ rằng bạn có thể chuyển một chuỗi truy vấn không? với làm mới trang, cách tiếp cận hiện tại sẽ không hoạt động.
renakre
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.