Как плавно изменять фон сайта при нажатии на определенное изображение/кнопку и запомнить выбранное изображение в текущей или следующих сессиях?

Сайт делаю на тильде, извините. Я только учусь и не умею писать полноценные коды. Перепробовал уйму вариантов с форумов, вопрос оказался актуальным, но ни один код не смог нормально вписать в тильду.

Каким способом я частично решил задачу: Создал 6 элементов. Первые 3 с изображениями имеют классы: uc-tab1, uc-tab2, uc-tab3. В 4-6 разместил 3 мини-изображения-кнопки с одинаковым классом: tab-btn и разными ссылками href="#tab1","#tab2","#tab3".

<style> /* Стиль кнопки для активного элемента */
.my-active-class {
    outline: 4px solid #fff !important;
    outline-offset: 6px;
}
</style>

<script>
    // Скрыть все вкладки, кроме первой
    $('[class*="uc-tab"]').not('.uc-tab1').fadeOut(0);

    // Добавить класс "bactive" для первой вкладки
    $('[href="#tab1"]').addClass('my-active-class');

    // Обработчик события для клика по кнопкам вкладок
    $('.tab-btn a').click(function() {
    // Убрать класс "bactive" у всех кнопок
    $('.tab-btn a').removeClass('my-active-class');

    // Добавить класс "my-active-class" к кнопке, по которой кликнули
    $(this).addClass('my-active-class');

    // Получить идентификатор вкладки из атрибута href кнопки
    var slide = $(this).attr('href').slice(1);

    // Скрыть все вкладки
    $('[class*="uc-tab"]').fadeOut(0);

    // Показать вкладку с идентификатором, соответствующим кнопке
    $('.uc-' + slide + '').fadeIn(0); 
    t_lazyload_update();
    
});
</script>

Работает это по принципу: показать выбранный блок и скрыть остальные. Но при перезагрузке - все возвращается к начальному состоянию. Где и как прописывать localStorage и sessionStorage я не знаю. И стоит ли вообще использовать такой костыльный код для моей задачи? Было бы очень здорово еще сделать плавную смену изображений, но это, наверное, я много хочу. Прошу помощи у вас господа программисты и жду ваши предложения.


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

Автор решения: De.Minov

В данном примере реализованна плавное изменение фона при помощи background-image и transition, но данный способ может работать не везде (Chrome на Window тут всё ок работает).
Так же тут реализовано сохранение выбранного фона в localStorage, но в сниппете это не работает.

Описание в коде.

// массив изображений для фона
const wallpapers = [
  'https://i.imgur.com/hspxf3p.png',
  'https://i.imgur.com/HKg999L.png',
  'https://i.imgur.com/EajFv0e.png'
];
const changeBg = $('.change-bg'); // блок куда будут создаваться элементы и там же выбираться
const toBg = $('body'); // блок где будет меняться фон

let isTransitionFlag = false; // флаг для плавности анимации смены фона
// в сниппете не работает localStorage (в целях безопасности), по этому в рабочем коде ниже строчку раскомментировать, а под ней удалить.
// const selectedBg = localStorage.getItem('body-bg') ? +(localStorage.getItem('body-bg')) : 0;
const selectedBg = 0;

toBg.css('background-image', `url(${wallpapers[selectedBg]})`); // если ранее был сохранён фон, то устанавливаем его

// добавляем варианты бэкграундов в блок
wallpapers.map(function(value, index) {
  const item = $('<div class="change-bg__item"></div>'); // создаём айтем
  const img = $('<div class="change-bg__item-img"></div>'); // вложенный блок
  img.css('background-image', `url(${value})`); // вложенному ставим изображение
  
  if(selectedBg === index) item.addClass('change-bg__item--active'); // если по индексу совпадение с выбранным, то выдаём айтему активный класс
  
  item.append(img); // добавляем вложенный в айтем
  changeBg.append(item); // добавляем айтем в блок с выбором
});

// смена фона
changeBg.on('click', '.change-bg__item', function() {
  if(isTransitionFlag === false && !$(this).hasClass('change-bg__item--active')) { // если класс не активый и флаг "выключен", то выполняем код ниже
    isTransitionFlag = true; // переключаем флаг
    changeBg.find('.change-bg__item--active').removeClass('change-bg__item--active'); // удаляем у предыдущего активного айтема активный класс
    $(this).addClass('change-bg__item--active'); // вешаем активный класс на нажатый
    
    const index = $(this).index(); // получаем индекс айтема
    toBg.css('background-image', `url(${wallpapers[index]})`); // по индексу выбираем и ставим фон
    // localStorage.setItem('body-bg', index); // сохраняем индекс в localStorage
    
    // запускаем таймер
    setTimeout(function() {
      isTransitionFlag = false; // после окончания таймера меняем обратно флаг
    }, 1000); // время таймера должно быть равным кол-во времени на transition background-image, в данном случае 1s == 1000 (ms)
    // Есть ивент transitionend, но в данном случае он не отрабатывает :\
  }
});
body {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100vh;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  margin: 0;
  transition: background-image 1s ease;
}

.change-bg {
  display: flex;
  gap: 10px;
}

.change-bg__item {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  border: 3px solid transparent;
  box-sizing: border-box;
  cursor: pointer;
  transition: border-color .3s ease;
}

.change-bg__item:not(.change-bg__item--active):hover {
  border-color: rgba(255,255,255, .5);
}

.change-bg__item--active {
  border-color: #fff;
}

.change-bg__item-img {
  width: calc(100% - 8px);
  height: calc(100% - 8px);
  border-radius: 50%;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<div class="change-bg"></div>


Вариант на JS:

// массив изображений для фона
const wallpapers = [
  'https://i.imgur.com/hspxf3p.png',
  'https://i.imgur.com/HKg999L.png',
  'https://i.imgur.com/EajFv0e.png'
];
const changeBg = document.querySelector('.change-bg');
const toBg = document.body;

let isTransitionFlag = false;
// в сниппете не работает localStorage (в целях безопасности), по этому в рабочем коде ниже строчку раскомментировать, а под ней удалить.
// const selectedBg = localStorage.getItem('body-bg') ? +(localStorage.getItem('body-bg')) : 0;
const selectedBg = 0;

toBg.style.backgroundImage = `url(${wallpapers[selectedBg]})`;

// добавляем варианты бэкграундов в блок
wallpapers.map(function(value, index) {
  const item = document.createElement('div');
  item.classList.add('change-bg__item');
  const img = document.createElement('div');
  img.classList.add('change-bg__item-img');
  img.style.backgroundImage = `url(${value})`;
  
  if(selectedBg === index) item.classList.add('change-bg__item--active');
  
  item.append(img);
  changeBg.append(item);
});

// смена фона
changeBg.addEventListener('click', (event) => {
  const target = event.target.closest('.change-bg__item');
  
  if(target && isTransitionFlag === false && !target.classList.contains('change-bg__item--active')) {
    isTransitionFlag = true;
    const oldActive = changeBg.querySelector('.change-bg__item--active')
    if(oldActive) oldActive.classList.remove('change-bg__item--active');
    target.classList.add('change-bg__item--active');
    
    const index = [...target.parentElement.children].indexOf(target);
    toBg.style.backgroundImage = `url(${wallpapers[index]})`;
    // localStorage.setItem('body-bg', index); // сохраняем индекс в localStorage
    
    // запускаем таймер
    setTimeout(function() {
      isTransitionFlag = false;
    }, 1000);
  }
});
body {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100vh;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  margin: 0;
  transition: background-image 1s ease;
}

.change-bg {
  display: flex;
  gap: 10px;
}

.change-bg__item {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  border: 3px solid transparent;
  box-sizing: border-box;
  cursor: pointer;
  transition: border-color .3s ease;
}

.change-bg__item:not(.change-bg__item--active):hover {
  border-color: rgba(255,255,255, .5);
}

.change-bg__item--active {
  border-color: #fff;
}

.change-bg__item-img {
  width: calc(100% - 8px);
  height: calc(100% - 8px);
  border-radius: 50%;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
}
<div class="change-bg"></div>

→ Ссылка