Как выбрать до 3 карточек, остальные сделать неактивными, все записать в localstorage и при загрузке все выводить как было?
Нужно выбирать до 3х карточек.
При достижении лимита отключаем остальные карточки.
Карточки по ID записываем в localStorage. И при загрузке страницы расставляем выбор как было.
Проблема в том, что при загрузке не все неактивные карточки становятся неактивными. А также можно выбрать больше ограничения. Казалось бы элементарная задача, а превратилась в нечто невозможное..
jsFiddle https://jsfiddle.net/Vaniljs/19muw4d7/59/
const limit = 3;
var arrForCheckedItem = []; // массив для сохранения el в localStorage
document.addEventListener('click', ({ target: t }) => {
if (t.classList.contains('product')) {
if (!t.classList.contains('unchecked')) {
arrForCheckedItem = []; // обнуляем массив, чтобы не копился
t.classList.toggle('checked');
document.querySelectorAll('.product.checked').forEach(i => {
if (i.classList.contains('checked')) {
arrForCheckedItem.push(i.dataset.productid); // Сохраняем выбранные el в массив
}
})
localStorage.setItem('checked_items', arrForCheckedItem); // Сохраняем массив в localStorage
const allChecked = document.querySelectorAll('.product.checked').length >= limit;
document.querySelectorAll('.product:not(.checked)').forEach(n => {
n.classList.toggle('unchecked', allChecked);
});
}
}
console.log(localStorage.getItem('checked_items')); // Проверка содержимого в localStorage
});
// ОТМЕЧАЕМ ВЫБРАННЫЕ И НЕВЫБРАННЫЕ ПРИ ЗАГРУЗКЕ СТРАНИЦЫ
window.addEventListener('load', () => {
let arrFromStorage = localStorage.getItem('checked_items'); // выгружаем данные из localStorage
let allCards = document.querySelectorAll('.product.slick-slide'); // выбираем все карточки
if (arrFromStorage.length) { // если localStorage существует
arrFromStorage.split(',').map(itemFromStorage => { // режем строку из localStorage в массив и перебираем
allCards.forEach(itemProduct => {
if (itemProduct.dataset.productid == itemFromStorage) { // если у карточки такой же id - отмечаем ее выбранной
itemProduct.classList.add('checked')
}
if (document.querySelectorAll('.product.slick-slide.checked').length >= limit && itemProduct.dataset.productid != itemFromStorage) { // если у карточки не такой же id b выбранных меньше лимита - отмечаем ее не выбранной
itemProduct.classList.add('unchecked')
}
})
})
}
})
div:not(.product) {
display: flex;
}
.product {
display: block;
width: 100px;
height: 100px;
margin: 20px;
background-color: gray;
border: 2px solid gray;
cursor: pointer;
}
.product.checked {
border: 2px solid green;
background-color: lightgray;
}
.product.unchecked {
border: 2px solid red;
background-color: darkgray;
cursor: not-allowed;
}
<div>
<div class="product slick-slide" data-productid="1">1</div>
<div class="product slick-slide" data-productid="2">2</div>
<div class="product slick-slide" data-productid="3">3</div>
<div class="product slick-slide" data-productid="4">4</div>
<div class="product slick-slide" data-productid="5">5</div>
<div class="product slick-slide" data-productid="6">6</div>
</div>
Ответы (2 шт):
Сделал форк от вашего fiddle: https://jsfiddle.net/4h0cu1wo/
Мне кажется, что выделение красным стоит сделать с помощью css. Таким образом, можно выделять красным все те, кто не имеет класс .checked, но только в случае, если в родителях есть класс .limit.
Если в процессе сохранить список с массивом из трех элементов, а потом уменьшить лимит до одного, выделен будет только первый, так как загрузка фактически имитирует последовательные нажатия по карточкам.
index.js:
const limit = 3; // Какой лимит выделяемых элементов
let selected = 0; // Количество выделенных на данный момент элементов
const cards = document.getElementById('cards') // Ссылка на контейнер всех карточек
cards.addEventListener('click', ({ target }) => {
if (target.dataset.productid) select(target) // Если нажали по карточке, пытаемся ее выделить
});
window.addEventListener('load', () => load()); // Выполняем загрузку при запуске страницы
// Выделение передаваемого элемента
function select(element) {
// Если лимит не достигнут или мы нажимаем по выделенному элементу...
if (selected < limit || element.classList.contains('checked')) {
element.classList.toggle('checked') // Переключаем .checked
selected += element.classList.contains('checked') ? 1 : -1 // Если .checked был добавлен, инкрементируем счетчик
cards.classList.toggle('limit', selected >= limit) // Если достигли лимита, добавляем класс .limit в контейнер
if (selected >= limit) save() // А так же, при достижении лимита сохраняем полученный список
}
}
// Сохранение списка выделенных карточек
function save() {
const items = []
// Проодим по всем элементам, у которых есть класс .checked
cards.querySelectorAll('.checked').forEach(element => items.push(element.dataset.productid));
localStorage.setItem('checked_items', items); // Сохраняем их в LocalStorage
}
// Загрузка списка выделенных карточек
function load() {
const items = localStorage.getItem('checked_items');
items.split(',').forEach(id => select(cards.querySelector(`[data-productid="${id}"]`))) // Передаем на выделение карточку с указанным id в dataset
}
index.css:
div#cards {
display: flex;
}
.product {
display: block;
width: 100px;
height: 100px;
margin: 20px;
background-color: gray;
border: 2px solid gray;
cursor: pointer;
}
.limit {
.product {
border: 2px solid red;
background-color: darkgray;
&:not(.checked) {
cursor: not-allowed;
}
}
}
.product.checked {
border: 2px solid green;
background-color: lightgray;
}
index.html:
<div id="cards">
<div class="product slick-slide" data-productid="1">1</div>
<div class="product slick-slide" data-productid="2">2</div>
<div class="product slick-slide" data-productid="3">3</div>
<div class="product slick-slide" data-productid="4">4</div>
<div class="product slick-slide" data-productid="5">5</div>
<div class="product slick-slide" data-productid="6">6</div>
</div>
window._cardsSelector = {
_f: {},
defaults: {
cardsLimit: 3,
selectors: {
card: 'div.card'
}
}
};
window._cardsSelector._f.save = () => {
let idList = [];
$(`${window._cardsSelector.defaults.selectors.card}.selected`)
.each((i, item) => {
idList.push($(item).data('card-id'));
});
localStorage.setItem('selected_cards', JSON.stringify(idList));
};
window._cardsSelector._f.load = () => {
let ids = JSON.parse(localStorage.getItem('selected_cards', '[]'));
ids.forEach(i => $(`div.card[data-card-id=${i}]`).addClass('selected'));
window._cardsSelector._f.check();
};
window._cardsSelector._f.check = () => {
let limit = window._cardsSelector.defaults.cardsLimit,
defaultSelector = $(`${window._cardsSelector.defaults.selectors.card}.selected`);
if (defaultSelector.length === limit) {
$(`${window._cardsSelector.defaults.selectors.card}:not(.selected)`)
.addClass('disabled');
} else {
$(`${window._cardsSelector.defaults.selectors.card}.disabled`)
.removeClass('disabled');
}
window._cardsSelector._f.save();
};
$(document).ready(function() {
window._cardsSelector._f.load();
$(window._cardsSelector.defaults.selectors.card)
.click(function() {
$(this).toggleClass('selected');
window._cardsSelector._f.check();
});
});
.cards {
width: 98% !important;
margin: 8px auto;
}
.cards>.card {
display: flex;
align-items: center;
justify-content: center;
min-height: 150px;
max-width: 200px;
padding: 12px;
margin: 4px;
box-shadow: 0 0 1px gray
}
.selected {
background: rgba(0, 160, 0, 0.07);
}
.disabled {
background: rgba(0, 0, 0, 0.07);
}
<script class="cssdeck" src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div class="cards">
<div class="card" data-card-id="1">
Card Item 1
</div>
<div class="card" data-card-id="2">
Card Item 2
</div>
<div class="card" data-card-id="3">
Card Item 3
</div>
<div class="card" data-card-id="4">
Card Item 4
</div>
<div class="card" data-card-id="5">
Card Item 5
</div>
<div class="card" data-card-id="6">
Card Item 6
</div>
</div>