Зберігати змінні між завантаженнями сторінок


96

Я намагаюся зафіксувати натискання кнопки подання моєї форми, і якщо форма надіслана, сторінка оновлюється, і я показую кілька прихованих полів. Я хотів би визначити, чи форма була надіслана раніше чи ні, і якщо вона надіслана при перезавантаженні, я хотів би показати приховані поля. Я намагався використати глобальну змінну для досягнення цього, проте мені не вдалося змусити її працювати належним чином.

Ось те, що я спробував:

  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
    }
  });

Будь-які пропозиції щодо того, що неправильно з цим кодом?


1
Я не думаю, що цього можна зробити без якогось сховища. Усі ваші змінні JS будуть очищені. Весь ваш обсяг буде перероблений.
— Дейв Альперович

Чому б вам не розмістити більшу частину сторінки в "частковому" і не оновити це?
— Дейв Альперович

Що таке часткове? На жаль, я цього не знаю.
— Неофіл

Ви розглядали можливість подати форму через ajax та показати поля після подання?
— dannyshaw

1
Чи можете ви детальніше пояснити, чому вам потрібно оновити сторінку? Якщо ми зможемо цього уникнути, ви зможете робити те, що хочете, якщо будете просто preventDefaultна submitзаході (замість того, що clickви використовуєте.)
— Пелег

Відповіді:


205

Оскільки HTTP не має статусу, кожен раз, коли ви завантажуєте сторінку, він використовуватиме початкові значення того, що ви встановили в JavaScript. Ви не можете встановити глобальну змінну в JS і просто змусити це значення залишатися після завантаження сторінки знову.

Є кілька способів зберегти значення в іншому місці, щоб можна було ініціалізувати його при завантаженні за допомогою JavaScript


Рядок запиту

Під час надсилання форми за допомогою GETметоду URL-адреса оновлюється за допомогою рядка запиту ( ?parameter=value&something=42). Ви можете використати це, встановивши для поля введення у форму певне значення. Це буде найпростіший приклад:

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

При початковому завантаженні сторінки рядок запиту не встановлюється. Коли ви подаєте цю форму, комбінація вхідних даних nameта valueкомбінація вхідних даних передаються у рядок запиту як clicked=true. Отже, коли сторінка знову завантажується за допомогою цього рядка запиту, ви можете перевірити, чи натиснуто кнопку.

Щоб прочитати ці дані, ви можете використовувати такий сценарій при завантаженні сторінки:

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');

( Джерело )

Можливість використовувати це залежить від того, як у даний час працює ваша форма; якщо ви вже використовуєте POST, це може бути проблематично.

Крім того, для більших наборів даних це менше, ніж оптимальне. Передача рядка не є великою проблемою, але для масивів та об’єктів даних вам слід використовувати веб-сховище або файли cookie. Хоча деталі дещо різняться між браузерами, практичне обмеження довжини URI становить близько 2000 символів


Веб-сховище

З введенням HTML5 ми також отримали веб-сховище, яке дозволяє зберігати інформацію в браузері при завантаженні сторінок. Існує localStorageможливість збереження даних протягом тривалого періоду (якщо користувач не видаляє їх вручну) і sessionStorageяка зберігає дані лише під час поточного сеансу перегляду. Останнє для вас тут корисно, оскільки ви не хочете, щоб "натиснуто" було встановлено в значення true, коли користувач повернеться пізніше.

Тут я встановив сховище для події натискання кнопки, але ви також можете прив'язати його до форми подання або чогось іншого.

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

Потім, завантажуючи сторінку, ви можете перевірити, чи встановлена ​​вона, використовуючи це:

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

Незважаючи на те, що це значення зберігається лише під час цього сеансу перегляду, можливо, ви хочете скинути його раніше. Для цього використовуйте:

sessionStorage.removeItem('clicked');

Якщо ви хочете зберегти об'єкт або масив JS, вам слід перетворити це на рядок. Відповідно до специфікації, має бути можливим збереження інших типів даних, але це ще неправильно реалізовано в браузерах.

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

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

Підтримка браузера є чудовою, тому ви повинні бути впевнені у використанні цього, якщо вам не потрібно підтримувати справді старі / неясні браузери. Веб-сховище - це майбутнє.


Печиво

Альтернативою веб-сховищу є збереження даних у файлі cookie. Файли cookie в основному створені для зчитування даних на стороні сервера, але можуть використовуватися і для суто клієнтських даних.

Ви вже використовуєте jQuery, що робить налаштування файлів cookie досить простим. Знову ж таки, я використовую clickподію тут, але міг би бути використаний де завгодно.

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

Тоді при завантаженні сторінки ви можете прочитати файл cookie так:

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

Оскільки у вашому випадку файли cookie зберігаються протягом сеансів, вам потрібно буде їх зняти, як тільки ви зробите все, що з цим потрібно. Ви не хотіли б, щоб користувач повернувся через день і все ще clickedвстановив значення true.

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

(не-jQuery спосіб встановити / прочитати файли cookie можна знайти тут )

Я особисто не використовував би cookie для чогось такого простого, як запам'ятовування клацаного стану, але якщо рядок запиту не є опцією, і вам потрібно підтримувати справді старі браузери, які не підтримують sessionStorage, це буде працювати. Вам слід спочатку здійснити це за допомогою перевірки sessionStorage, і лише якщо це не вдається, використовуйте метод cookie.


window.name

Хоча це здається мені зламаною, яка, ймовірно, виникла ще до localStorage / sessionStorage, ви можете зберігати інформацію у window.nameвластивості:

window.name = "my value"

Він може зберігати лише рядки, тому, якщо ви хочете зберегти об’єкт, вам доведеться його обстежити, як у наведеному вище localStorageприкладі:

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

Основна відмінність полягає в тому, що ця інформація зберігається не тільки в оновлених сторінках, але й у різних доменах. Однак це обмежено поточною вкладкою, в якій ви перебуваєте.

Це означає, що ви можете зберегти деяку інформацію на своїй сторінці, і поки користувач залишається на цій вкладці, ви можете отримати доступ до тієї самої інформації, навіть якщо він переглядав інший веб-сайт і назад. Загалом, я б радив не використовувати це, якщо вам не потрібно фактично зберігати міждоменну інформацію під час одного сеансу перегляду.


9
Тьфу, лише після написання я прочитав ваш опис щедрості, в якому говорилося "ні файлів cookie, ні локального сховища". Я залишатиму цей коментар незмінним для інших, кому він може знадобитися, але вам просто потрібно використовувати рядок запиту, я думаю.
— Стефан Мюллер,

1
В основному я вже використовую localStorage у багатьох випадках для свого веб-додатку, і я хотів би уникати використання занадто багатьох змінних localStorage. Однак мені подобається ідея видалення елемента localStorage, коли я закінчу з ним. Це було те, про що я не думав, використовуючи мою змінну localStorage.
— Неофіл

3
У разі запиту на пост ви можете змінити дію -attribute $ ("# formid"). Attr ("action", url + "& clicked = 1"), а також виявити GET або POST з $ ("# formid"). Attr ( "метод"), але це може не вирішити спосіб виявлення проблеми перезавантаження
— Теро Толонен

2
@TheNewbie минув деякий час з моменту написання цієї відповіді, але я щойно додав нову опцію ( window.name). Він може просто робити саме те, що вам потрібно, не використовуючи файли cookie / localStorage.
— Стефан Мюллер,

1
Я хотів додати, що локальне та сесійне сховище також не є повністю надійними в нових браузерах. Зазвичай є запасний варіант до window.name.
— JavaScript

5

Спробуйте використати $.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

Використання localeStorageабо, sessionStorageздається, найкращий вибір.

Замість збереження clickedзмінної в області глобулу зберігайте її таким чином:

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
    }

});

Я маю намір не використовувати localstorage або sessionStorage бажано.
— Неофіл

-5

Ви можете спробувати це:

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

Коли сторінка перезавантажується, все одно отримують натиснуте значення як false.
— Неофіл

1
@TheNewbie, ти думаєш, що ти можеш передати рядок запиту? при оновленні сторінки поточний підхід не буде працювати.
— renakre
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.