Как сохранить параметры JS при обновлении страницы (скрипт изменения стиля отображения вида карточек товара)

Всем добрый день. Есть простой не замысловатый код:

const listViewButton = document.querySelector('.list-view-button');
const gridViewButton = document.querySelector('.grid-view-button');
const list = document.querySelector('ol');

listViewButton.onclick = function() {
  list.classList.remove('grid-view-filter');
  list.classList.add('list-view-filter');
}

gridViewButton.onclick = function() {
  list.classList.remove('list-view-filter');
  list.classList.add('grid-view-filter');
}
body {
  font-family: 'Helvetica';
  background-color: #0e2439;
}

.filter-buttons {
  display: flex;
  margin-bottom: 20px;
}

.list-view-button,
.grid-view-button {
  color: white;
  border: 1px solid white;
  padding: 5px;
  font-size: 14px;
  cursor: pointer;
  border-radius: 3px;
}

.list-view-button:hover,
.grid-view-button:hover {
  background: white;
  color: #0e2439;
}

.list-view-button {
  margin-right: 10px;
}

.list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
}

li {
  background-color: #1f364d;
  color: white;
  border-radius: 3px;
  margin-bottom: 10px;
  transition: 0.3s;
}

.list.list-view-filter {
  flex-direction: column;
}

.list.list-view-filter li {
  padding: 10px;
}

.list.grid-view-filter {
  flex-flow: row wrap;
}

.list.grid-view-filter li {
  width: calc(50% - 210px);
  padding: 100px;
  margin-right: 10px;
  text-align: center;
}
<div class="filter-buttons">
  <div class="list-view-button"><i class="fa fa-bars" aria-hidden="true"></i> List view</div>
  <div class="grid-view-button"><i class="fa fa-th-large" aria-hidden="true"></i> Grid view</div>
</div>

<ol class="list list-view-filter">
  <li>List item 1</li>
  <li>List item 2</li>
  <li>List item 3</li>
  <li>List item 4</li>
  <li>List item 5</li>
  <li>List item 6</li>
</ol>

Я не знаю как добавить JS (не спец в JS) чтобы сохраняло параметры в браузере даже в рамках 1-ой сессии


Ответы (2 шт):

Автор решения: Alex

Самое простое - пиши в кастомные куки инфу о включенных опциях, типо кука пусть называется user_view и в ней значение list или grid, при загрузке документа пытайся считать куку, если нет - ставим дефолтный вид, если есть - ставим то что выбрано, но надо учитывать что в сафари еще с прошлого года конкретно так порезали время жизни куки на уровне браузера, в хроме тоже вроде как недавно то же самое сделали, короче вечную куку уже не создашь

→ Ссылка
Автор решения: Евгений Кулик

Написал пример с использованием cookie и localStorage? в скрипте есть переменная cookieOrLocal, если cookieOrLocal = 'localStorage'. то скрипт будет брать settings из localstorage, соответственно, если cookieOrLocal = 'cookie', то данные будут браться из cookie? это чтобы Вы понялм принцип работы того и другого. В скрипте есть имитация пагинации.

ВНИМАНИЕ! - stackoverflow не разрешает использовать cookie и localStorage, скопируйте код локально и запустите

const buttonsList = document.querySelectorAll('.content-settings-icon')
const buttons = document.querySelectorAll('button')
const list = document.querySelector('.products')
const pagination = document.querySelectorAll('.pagination-element')
let localSettings = ''
let cookieSettings = ''

/** 'cookie' - данные берутся из cookie
 ** 'localStorage' - данные берутся из localStorage
 **/
let cookieOrLocal = 'localStorage' // cookie || localStorage

console.log('Данные берутся из '+cookieOrLocal)

/** функция для получения переменной из cookie по имени */
function getCookie(name) {
    let matches = document.cookie.match(new RegExp(
        "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
    ));
    return matches ? decodeURIComponent(matches[1]) : undefined;
}

if(cookieOrLocal === 'cookie') {
    cookieSettings = JSON.parse(getCookie('settings'))
} else if(cookieOrLocal === 'localStorage') {
    localSettings = JSON.parse(localStorage.getItem('settings'))
}

/** стартовые настрйоки */
let settings = {
    page: '1',
    listStyle: 'grid',
    elementsStart: 1,
    elementsEnd: 8
}

/** если есть что-то в localStorage, то берем значения оттуда  */
if(localSettings) {
    settings = localSettings
} else if(cookieSettings) {
    settings = cookieSettings
}

/** добавляем класс для списка продуктов */
list.classList.add(settings.listStyle)

/** имитация страниц */
const clickOnPagination = (e) => {
    settings.page = e.target.dataset.page
    if(settings.page === '1') {
        settings.elementsStart = 1
        settings.elementsEnd = 8
    } else if(settings.page === '2') {
        settings.elementsStart = 9
        settings.elementsEnd = 16
    } else if(settings.page === '3') {
        settings.elementsStart = 17
        settings.elementsEnd = 24
    }
    localStorage.setItem('settings', JSON.stringify(settings))
    document.cookie = "settings="+JSON.stringify(settings)
}

/** отрисовываем продукты */
for(let i = settings.elementsStart; i <= settings.elementsEnd; i++) {
    let element = document.createElement('li')
    element.textContent = i
    list.appendChild(element)
}

/** нажатие на иконки */
const clickOnButton = (e) => {
    if(e.target.classList.contains('active')) return
    
    /** удаляем у всех кнопок класс active */
    buttonsList.forEach(btn => {
        btn.classList.remove('active')
    })
    
    /** удаляем ткущий класс у списка */
    list.classList.remove(settings.listStyle)
    
    /** добавить класс active нажатому элементу */
    e.target.classList.add('active')
    
    /** обновляем settings */
    settings.listStyle = e.target.dataset.list
    
    /** добавляем новый класс списку */
    list.classList.add(settings.listStyle)
    
    /** сохраняем settings в localStorage */
    localStorage.setItem('settings', JSON.stringify(settings))
    
    /** сохраняем settings в cookie */
    document.cookie = "settings="+JSON.stringify(settings)
}

buttonsList.forEach(btn => {
    if(btn.dataset.list === settings.listStyle) btn.classList.add('active')
    btn.addEventListener('click', clickOnButton)
})

pagination.forEach(item => {
    if(item.dataset.page === settings.page) {
        item.classList.add('active')
    }
    item.addEventListener('click', clickOnPagination)
})
body {
    font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
}

.content-settings {
    margin: 20px 0;
    text-align: right;
}

.content-settings span {
    display: inline-block;
}

.content-settings-icon {
    border: 1px solid #ccc;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 25px;
    height: 25px;
    border-radius: 5px;
    padding: 3px;
    margin: 0 3px;
    cursor: pointer;
}

.content-settings-icon:hover {
    background-color: #eee;
}

.content-settings-icon.active {
    background-color: cornflowerblue;
}

.content-settings-icon svg {
    pointer-events: none;
    width: 100%;
    height: 100%;
}

.content-settings-icon svg path {
    fill: #999;
}

.content-settings-icon.active svg path {
    fill: #fff;
}

ul {
    list-style: none;
    margin: 0;
    padding: 0;
}


.products {
    background-color: #eee;
    margin-bottom: 20px;
}

.products.list {
    display: block;
    padding: 5px 0;
}

.products.list li {
    margin: 5px 10px 10px;
}

.products.grid {
    padding: 10px;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr;
    gap: 10px 10px;
    grid-template-areas:
    ". . . ."
    ". . . .";
}

.products li {
    border: 1px solid #ccc;
    background-color: #f5f5f5;
    flex: 1 1 20%;
    padding: 10px 20px;
    font-size: 32px;
    font-weight: 700;
    color: #999;
    border-radius: 5px;
}

.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
}

.pagination li a {
    border: 1px solid #ccc;
    display: inline-block;
    padding: 5px 10px;
    margin: 0 3px;
    text-decoration: none;
    color: #999999;
    border-radius: 3px;
    font-weight: 700;
}

.pagination li a:hover {
    background-color: #eee;
}

.pagination li a.active {
    background-color: #ddd;
}

button {
    background-color: #eee;
    border: 1px solid #ccc;
    border-radius: 3px;
    margin: 0 5px;
    padding: 5px 10px;
    cursor: pointer;
}

button:hover {
    background-color: #e5e5e5;
}

button.active {
    background-color: cornflowerblue;
    color: #fff;
}
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="content">
        <div class="content-settings">
            <div class="content-settings-icon" data-list="grid"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20.25 12.0283C21.2165 12.0283 22 12.8118 22 13.7783V16.2783C22 17.2448 21.2165 18.0283 20.25 18.0283H17.75C16.7835 18.0283 16 17.2448 16 16.2783V13.7783C16 12.8118 16.7835 12.0283 17.75 12.0283H20.25ZM6.25 12.0283C7.2165 12.0283 8 12.8118 8 13.7783V16.2783C8 17.2448 7.2165 18.0283 6.25 18.0283H3.75C2.7835 18.0283 2 17.2448 2 16.2783V13.7783C2 12.8118 2.7835 12.0283 3.75 12.0283H6.25ZM13.25 12.0283C14.2165 12.0283 15 12.8118 15 13.7783V16.2783C15 17.2448 14.2165 18.0283 13.25 18.0283H10.75C9.7835 18.0283 9 17.2448 9 16.2783V13.7783C9 12.8118 9.7835 12.0283 10.75 12.0283H13.25ZM13.25 5.02832C14.2165 5.02832 15 5.81182 15 6.77832V9.27832C15 10.2448 14.2165 11.0283 13.25 11.0283H10.75C9.7835 11.0283 9 10.2448 9 9.27832V6.77832C9 5.81182 9.7835 5.02832 10.75 5.02832H13.25ZM20.25 5.02832C21.2165 5.02832 22 5.81182 22 6.77832V9.27832C22 10.2448 21.2165 11.0283 20.25 11.0283H17.75C16.7835 11.0283 16 10.2448 16 9.27832V6.77832C16 5.81182 16.7835 5.02832 17.75 5.02832H20.25ZM6.25 5.02832C7.2165 5.02832 8 5.81182 8 6.77832V9.27832C8 10.2448 7.2165 11.0283 6.25 11.0283H3.75C2.7835 11.0283 2 10.2448 2 9.27832V6.77832C2 5.86015 2.70711 5.10713 3.60647 5.03412L3.75 5.02832H6.25Z" fill="#212121"/></svg></div>
            <div class="content-settings-icon" data-list="list"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.75 2.02002C4.7835 2.02002 4 2.80352 4 3.77002V6.27002C4 7.23652 4.7835 8.02002 5.75 8.02002H18.25C19.2165 8.02002 20 7.23652 20 6.27002V3.77002C20 2.80352 19.2165 2.02002 18.25 2.02002H5.75Z" fill="#212121"/><path d="M5.75 9.02002C4.7835 9.02002 4 9.80352 4 10.77V13.27C4 14.2365 4.7835 15.02 5.75 15.02H18.25C19.2165 15.02 20 14.2365 20 13.27V10.77C20 9.80352 19.2165 9.02002 18.25 9.02002H5.75Z" fill="#212121"/><path d="M5.75 16.02C4.7835 16.02 4 16.8035 4 17.77V20.27C4 21.2365 4.7835 22.02 5.75 22.02H18.25C19.2165 22.02 20 21.2365 20 20.27V17.77C20 16.8035 19.2165 16.02 18.25 16.02H5.75Z" fill="#212121"/></svg></div>
        </div>
        <ul class="products">
        
        </ul>
    </div>
    
    <ul class="pagination">
        <li><a href="?page=1" class="pagination-element" data-page="1">1</a></li>
        <li><a href="?page=2" class="pagination-element" data-page="2">2</a></li>
        <li><a href="?page=3" class="pagination-element" data-page="3">3</a></li>
    </ul>
<script src="scripts.js"></script>
</body>
</html>

→ Ссылка