Несохраненное состояние флажка с помощью localStorage в Chrome и Edge

Я пытаюсь сохранить и восстановить состояние checkbox и других элементов, используя localStorage, когда пользователь дублирует или закрывает вкладку. Это работает хорошо, когда у меня есть только checkbox, но как только я добавляю дополнительные элементы, состояние checkbox не сохраняется правильно в Chrome и Edge. Вдохновленный аналогичной проблемой, обсуждавшейся здесь, я создал версию, демонстрирующую проблему:

function save() {
  var checkbox = document.getElementById('checkbox1zaal1');
  var textarea = document.querySelector('textarea');
  localStorage.setItem('checkbox1zaal1', checkbox.checked);
  localStorage.setItem('box', textarea.value);
}

function load() {
  var checked = JSON.parse(localStorage.getItem('checkbox1zaal1'));
  document.getElementById("checkbox1zaal1").checked = checked;
  document.querySelector('textarea').value = JSON.parse(localStorage.getItem('box'));
}

function wis() {
  location.reload();
  localStorage.clear();
}

load();
<input type = "button" id = "ReserveerButton1" value = "save" onclick = "save()" />
<input type = "button" id = "Wisbutton1" value = "delete" onclick = "wis()" />
<input type = "checkbox" id = "checkbox1zaal1">
<textarea>Hello, world!</textarea>

ДЕМО

Действия по воспроизведению проблемы:

  1. Перейдите на демо-страницу.
  2. Просто установите флажок.
  3. Нажмите кнопку «Сохранить».
  4. Дублируйте вкладку.

Флажок на вкладке дубликатов не установлен.

Что мне не хватает? Это известная ошибка в Chrome и Edge, или есть другой подход, который я могу попробовать, чтобы гарантировать, что состояние checkbox сохраняется правильно вместе с другими элементами?

@CBroe: «зачем анализировать это как JSON, если вы вообще никогда не кодировали его как JSON?» Согласно dfsq в его посте, он используется для изменения типа string на boolean. Я просто пытался скопировать его скрипку.

Mori 02.07.2024 13:08

Хорошо, а что вы уже сделали, чтобы попытаться отладить это? Вы проверили, какие значения были сохранены, какие были прочитаны?

CBroe 02.07.2024 13:12

@CBroe: Я пробовал разные элементы формы, и, похоже, их значения сохраняются и восстанавливаются без проблем. Однако когда дело доходит до checkbox, Chrome и Edge не могут правильно отображать сохраненные данные.

Mori 02.07.2024 13:17

Так что же сохраняется? Пройдите проверку с помощью инструментов разработчика вашего браузера и запишите значение checked внутри load на консоль.

CBroe 02.07.2024 13:21

@CBroe: я проверяю checkbox, дублирую вкладку, а настоящий checkbox на странице не проверяется, хотя в консоли у меня есть следующее: console.info(checked); // true Это странно!

Mori 02.07.2024 14:04

У меня это отлично работает в Chrome с приведенным выше демонстрационным URL-адресом. Не имеет значения, перезагружаю ли я текущую вкладку или открываю ее снова в новой — флажок всегда принимает предыдущее состояние save-d.

CBroe 02.07.2024 14:09

@CBroe: Пожалуйста, попробуйте, не редактируя textarea.

Mori 02.07.2024 14:12

Это тоже работает; но текстовое поле выдает ошибки - потому что значение, которое вы для этого сохраняете, не может быть проанализировано как JSON. Поэтому удалите JSON.parse для текстового поля.

CBroe 02.07.2024 14:16

@CBroe: Боюсь, нет. Он неправильно отображает сохраненное состояние checkbox. Я использую последнюю версию Chrome для Windows и macOS. Пожалуйста, удалите данные просмотра и повторите попытку.

Mori 02.07.2024 14:25

Даже когда я пытаюсь перейти на приватную вкладку (поэтому нет существующей истории данных просмотра) - те же результаты. Может быть, у вас какое-то расширение браузера мешает?

CBroe 02.07.2024 14:28

@CBroe: никакого расширения. Это странно! Я просто открываю демо-страницу, проверяю checkbox, нажимаю кнопку «Сохранить» и дублирую вкладку. В новой вкладке checkbox не отмечен.

Mori 02.07.2024 14:34

На основе предоставленной вами демонстрации я провел тест, но не воспроизвел описанную вами проблему с флажком в Edge и Chrome. Пожалуйста, предоставьте воспроизводимую демонстрацию или расскажите мне более подробные шаги по воспроизведению. Кроме того, какая у вас версия Edge?

kobewang 03.07.2024 08:30

@kobewang: «Пожалуйста, предоставьте воспроизводимую демонстрацию или расскажите мне более подробные шаги по воспроизведению». Демо-версию можно воспроизвести: перейдите на демо-страницу. Установите флажок. Нажмите кнопку «Сохранить», а затем дублируйте вкладку. Флажок на вкладке дубликатов не установлен. Chrome: 126.0.6478.127 (официальная сборка) (64-разрядная версия), Edge: 126.0.2592.87 (официальная сборка) (64-разрядная версия)

Mori 03.07.2024 10:20

@CBroe Может воспроизводиться в Chrome 126.0.6478.127 в Windows и OSX. Но только для начальной загрузки второй вкладки после "щелчок правой кнопкой мыши -> Дублировать". Т.е. если я обновлю вторую вкладку, значения будут установлены правильно. Я также исправил ошибки с помощью JSON.parse, которые не повлияли на такое поведение.

derpirscher 04.07.2024 20:02

@kobewang Я могу прекрасно воспроизвести, выполнив точные действия, указанные выше ... (т. е. «дублировать вкладку», что означает «щелкнуть правой кнопкой мыши по вкладке -> дублировать»)

derpirscher 04.07.2024 20:08

Нет необходимости анализировать json для текстовой области. document.querySelector('textarea').value = localStorage.getItem('box');. Это решит вашу проблему

Anh Tuấn Nguyễn 11.07.2024 11:26
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
16
346
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

ДОБАВЛЯТЬ :

var as = document.getElementById('textbox').value
//Code to sent to discord webhook
sent(as)

Каким должен быть sent?

derpirscher 04.07.2024 20:13

Это похоже на функцию для отправки в веб-хук Discord, я не могу это сделать, поэтому вы просто добавляете саму функцию для отправки, обработки и прочего.

Syaamil Maulana 10.07.2024 12:01

Так какое отношение к этому вопросу имеет смерть?

derpirscher 10.07.2024 12:49

Я выполнил шаги, которые вы предоставили, чтобы воспроизвести проблему, но это не воспроизвело ее. Но когда я отключил настройку «Разрешить сайтам сохранять и читать данные cookie (рекомендуется)», я смог воспроизвести проблему. Поэтому введите «edge://settings/content/cookies» в адресной строке Edge и проверьте, не отключен ли этот параметр, чтобы вызвать эту проблему.

Отключение этого параметра предотвращает запись Edge в локальное хранилище. Но, как подтвердил ОП, запись в локальное хранилище работает, этот параметр явно включен...

derpirscher 04.07.2024 23:43
Ответ принят как подходящий

В вашем коде есть одна серьезная проблема: вы используете JSON.parse, фактически JSON.stringify не обрабатывая значения, которые вы пытаетесь проанализировать позже. Это приводит к ошибке при попытке проанализировать значение textarea. Эту ошибку легко увидеть, открыв инструменты разработчика Chrome...

Поэтому я бы посоветовал исправить ваш load, избавившись от JSON.parse.

function load(){
    var checked = localStorage.getItem('checkbox1zaal1') === "true";
    document.getElementById("checkbox1zaal1").checked = checked;
    document.querySelector('textarea').value = localStorage.getItem('box');
}

Но даже после исправления этой ошибки она по-прежнему не работает должным образом (по крайней мере, в браузерах на базе Chrome. Работает с Safari). Однако не знаю, почему это не удается, потому что (по крайней мере, для меня) происходит сбой только при начальной загрузке на новой вкладке. Т.е. если я сделаю «Обновить» на вновь созданной вкладке, она будет работать как положено.

Но я смогу заставить его работать, если сделаю

setTimeout(load, 0)

вместо

load();

Похоже, это какая-то проблема с синхронизацией или состояние гонки в движке браузера. Может быть, кто-то с большим пониманием сможет дать здесь объяснение. Используя setTimeout, мы фактически больше не вызываем load синхронно в процессе рендеринга, а только после завершения рендеринга. Кажется, здесь есть разница...

Также кажется странным, что флажок на вкладке «Дублировать» на самом деле снят, потому что, если я полностью удалю вызов load, «Дублировать вкладку» восстановит значения входных данных, как если бы они были на вкладке источника ... Так что, возможно, это конфликт/проблема времени между восстановлением входных значений с помощью операций «Дублировать» и обновлением входных данных из сценария. Это предположение также может объяснить, почему все работает так, как ожидалось, если выполнить «Обновить» на дублированной вкладке. И что еще более странно, это также работает, если textarea не пуст при сохранении или когда я полностью удаляю textarea и весь связанный с ним код...

Так что, вероятно, это не тот канонический ответ, который вы ищете. На мой взгляд, это больше похоже на ошибку в Chrome (и производных браузерах, таких как Edge или Brave). Тем более, что он работает так, как и ожидалось, в браузерах, отличных от Chrome, таких как Safari или Firefox, а также работает в браузерах на базе Chrome, когда вы обновляете или просто вставляете URL-адрес в новую пустую вкладку. Возможно, это даже зависит от версии и/или версии ОС, потому что она вполне работает и для других пользователей в Chrome. Вы можете попробовать сообщить о проблеме в Chromium (но я предлагаю сначала исправить ошибки с помощью JSON.parse)

Ваш код отлично работает с последней версией Chrome на MacOS, конечно, если скрипт размещен после других элементов HTML (после textarea) или, по крайней мере, первоначальный вызов load() выполняется на DOMContentLoaded. На какой ОС вы тестируете?

kikon 08.07.2024 02:53

@kikon Я могу воспроизвести проблему с Chrome 126.0.6478.127 на MacOS ventura, Windows 10 и Windows 11. Но только в конкретных ситуациях, которые я указал в ответе ...

derpirscher 08.07.2024 10:15

А также на Edge 126.0.2592.87 на Windows 11

derpirscher 08.07.2024 10:22

Я сообщил о проблеме в систему отслеживания ошибок Google, и они подтвердили, что могут воспроизвести эту проблему для версий начиная с 116 до текущей стабильной версии, а также для версий в будущих каналах выпуска бета-версии, dev и canary.

derpirscher 08.07.2024 17:29

Проблема:

Вы пытаетесь сохранить и восстановить состояние флажка вместе с другими элементами, используя localStorage. Хотя он работает только с флажком, введение дополнительных элементов (например, текстовой области) может привести к тому, что состояние флажка не будет правильно сохраняться в Chrome и Edge при дублировании вкладок.

Причина:

Между рендерингом браузера и вашим кодом JavaScript существует состояние гонки. Когда вы загружаете данные из localStorage (с помощью функции загрузки), браузер может отображать такие элементы, как текстовая область, прежде чем устанавливать ее значение. Это может перезаписать сохраненное состояние флажка в localStorage, когда вы позже вызовете функцию сохранения.

Решение:

Есть два подхода к решению этой проблемы:

Использование setTimeout:

Оберните вызов функции загрузки внутри setTimeout с задержкой 0. Это гарантирует выполнение загрузки после завершения рендеринга браузера:

function load() {
  setTimeout(function() {
    var checked = localStorage.getItem('checkbox1zaal1') === 'true'; // No need for JSON.parse for booleans
    document.getElementById("checkbox1zaal1").checked = checked;
    var textarea = document.querySelector('textarea');
    textarea.value = JSON.parse(localStorage.getItem('box'));
  }, 0);
}

Использование события хранения:

Прослушивайте событие хранения объекта окна. Это событие срабатывает всякий раз, когда изменяется localStorage. Вы можете проверить изменения в конкретном ключе, который вы используете для флажка, и соответствующим образом обновить его состояние:

window.addEventListener('storage', function(event) {
  if (event.key === 'checkbox1zaal1') {
    var checked = event.newValue === 'true'; // No need for JSON.parse for booleans
    document.getElementById("checkbox1zaal1").checked = checked;
  }
});

load();

Дополнительные баллы:

Вы можете напрямую использовать localStorage.setItem('checkbox1zaal1', checkbox.checked) для хранения логических значений (проверенное состояние) в localStorage. Не забудьте очистить localStorage, когда пользователь явно удаляет данные (с помощью кнопки «Удалить»).

Верхняя половина этого ответа просто перефразирует мой ответ, полученный несколько дней назад. И часть с событием хранилища не имеет никакого смысла в этом вопросе, потому что речь идет не о синхронизации, и событие хранилища не будет вызываться при открытии новой вкладки.

derpirscher 09.07.2024 09:03

Я не уверен, что это известная ошибка, но это ошибка со стороны Chrome. Я предполагаю, что это связано с тем, что эта duplication функция не стандартизирована, и, очевидно, их метод борьбы с дублированием все еще не завершен.

Итак, прибегнем к обходным путям!

Новое решение

<body>
  <input type = "button" id = "ReserveerButton1" value = "save" onclick = "save()">
  <input type = "button" id = "Wisbutton1" value = "delete" onclick = "wis()">
  <input type = "checkbox" id = "checkbox1zaal1">
  <textarea>Hello, World!</textarea>
  <script>
    // Treat this as a constant, in real app, you can use `const`
    // We're now limiting ourselves to es5
    var CHECKBOX_NAME = 'checkbox-' + Math.random().toString().substring(2, 8);
    var DEFAULT_TEXTAREA_VALUE = 'Hello, World!';

    function save() {
      var checkbox = document.getElementById('checkbox1zaal1');
      var textarea = document.querySelector('textarea');

      if (checkbox.checked) {
        localStorage.setItem('checkbox1zaal1', '1');
      } else {
        localStorage.removeItem('checkbox1zaal1');
      }
      localStorage.setItem('box', textarea.value);
    }

    function load() {
      var textarea = document.querySelector('textarea');
      textarea.value = localStorage.getItem('box') || DEFAULT_TEXTAREA_VALUE;

      var checkbox = document.getElementById('checkbox1zaal1');
      checkbox.name = CHECKBOX_NAME;
      localStorage.getItem('checkbox1zaal1') === '1' && 
        checkbox.setAttribute('checked', 'checked');
    }

    function wis() {
      location.reload();
      localStorage.clear();
    }

    load();
  </script>
</body>

Очевидно, использование другого флажка name for позволяет браузеру правильно загрузить значение. Не волнуйтесь, хотя мы создаем флажок name динамически выше, мы все равно можем отслеживать его, используя постоянный идентификатор.

Н.Б. Взял на себя смелость провести рефакторинг, систематизировать и устранить некоторые ошибки синтаксического анализа.

Предыдущее решение

Вот попытка -

function load() {
  var checked = JSON.parse(localStorage.getItem('checkbox1zaal1'));
  if (checked) {
    document.getElementById("checkbox1zaal1").click();
  }
  document.querySelector('textarea').value = JSON.parse(localStorage.getItem('box'));
}

Вместо установки атрибута checked мы вызываем щелчок, чтобы они проверили этот элемент!

Н.Б.

  • Вам все еще нужно исправить JSON-анализ вашего значения текстовой области, здесь я рассматриваю только получение состояния флажка!
  • Очевидно, это все еще не работает в Edge. Кажется, что использование setTimeout для выполнения load — такой же хороший обходной путь, как и следующий!

Довольно сложный подход, если всю проблему можно решить с помощью простого setTimeout(load, 0) и, возможно, это будет исправлено в ближайшем выпуске Chrome.

derpirscher 10.07.2024 17:37

Я только что провел рефакторинг кода, чтобы кое-что исправить. Кроме этого, единственное, что здесь важно, — это прикрепить уникальный name к вводу флажка. Не думайте, что это сложный подход. Если код вас смущает, возьмите код автора и попробуйте добавить следующую однострочную строку в функцию load после первой строки функции: document.getElementById("checkbox1zaal1").name = 'checkbox-' + Math.random().toString ().подстрока(2, 8);

hn719 10.07.2024 17:57

Нет, меня это не смущает, но установка случайных имен для формирования входных данных не всегда возможна, потому что обычно, когда кто-то использует имя для входных данных, это имя несет определенную семантику.

derpirscher 10.07.2024 19:13

:) Очень распространенная проблема с vanilla js. Нам нужно подумать о трёх вещах. Изменение пользовательского интерфейса, изменение СОСТОЯНИЯ, а также сохранит ли пользователь это состояние или нет.

Поэтому я немного обновил ваш код. Пожалуйста, дайте мне знать, если вам нужно больше объяснений, кроме комментариев.

<!doctype html>
<html lang = "en">

<head>
    <meta charset = "utf-8">
    <meta name = "viewport" content = "width=device-width, initial-scale=1">
    <title>Unsaved Checkbox State with localStorage in Chrome and Edge - Labground</title>
    <link rel = "icon" href = "/images/lab.svg" type = "image/svg+xml">
</head>

<body>
<input type = "button" id = "ReserveerButton1" value = "save" onclick = "save()">
<input type = "button" id = "Wisbutton1" value = "delete" onclick = "wis()">
<input type = "checkbox" id = "checkbox1zaal1">
<textarea></textarea>
<script>
    const DOM_ELEMENTS = {
        checkbox: document.getElementById('checkbox1zaal1'),
        textarea: document.querySelector('textarea')
    }

    const EL_STATE = {
        checkbox: JSON.parse(localStorage.getItem('checkbox1zaal1')),
        textarea: localStorage.getItem('box')
    }


    function wis() {
        localStorage.clear();
        location.reload();
    }

    // Save
    function save() {
        localStorage.setItem('checkbox1zaal1', DOM_ELEMENTS.checkbox.checked);
        localStorage.setItem('box', DOM_ELEMENTS.textarea.value);
    }


    // Onload function.
    (function() {
        // Get checkbox state
        if (EL_STATE.checkbox === null) {
            EL_STATE.checkbox = false;
            localStorage.setItem('checkbox1zaal1', EL_STATE.checkbox);
        } else {
            localStorage.setItem('checkbox1zaal1', EL_STATE.checkbox);
        }
        // UI checkbox state
        DOM_ELEMENTS.checkbox.checked = EL_STATE.checkbox;


        // Get textarea state
        if (EL_STATE.textarea === null) {
            EL_STATE.textarea = 'Hello World!!!';
            localStorage.setItem('box', EL_STATE.textarea);
        } else {
            localStorage.setItem('box', EL_STATE.textarea);
        }
        // UI textarea state
        DOM_ELEMENTS.textarea.value = EL_STATE.textarea;

        // Listen on changes of the checkbox UI and UPDATE state each time the checkbox is change
        DOM_ELEMENTS.checkbox.addEventListener('click', (event) => {
            EL_STATE.checkbox = event.target.checked;
        });

        // Listen on changes of the textbox UI and UPDATE state each time the value is change
        DOM_ELEMENTS.textarea.addEventListener('input', (event) => {
            EL_STATE.textarea = event.target.value;
        });
    })();

</script>
</body>

</html>

Почему это «очень распространенная проблема»? На самом деле это не потому, что вся эта проблема возникает только в очень специфической ситуации, которая, скорее всего, связана с браузером, а не с кодом...

derpirscher 10.07.2024 17:36

эй @derpirscher Мне плохо. Я не заключал в кавычки «очень распространенную проблему с JS» :) Я упомянул об этом, потому что мы забыли базовый процесс работы JS-движка, поскольку большинство из нас (включая меня) используем фреймворки, которые выполняют эту работу «из коробки», поскольку мы все ленивы :) . Я подробно описал этот код, чтобы показать, почему нам нужно обновлять UI и STATE отдельно, не предполагая, что значения являются типами по умолчанию.

Ploutarchos Michaelides 10.07.2024 19:28

Другие вопросы по теме