Вариантов создания корзины с использованием jQuery, на просторах интернета достаточно, но так как не все хотят подключать громоздкие библиотеки, особенно для каких-то разовых задач, я хочу показать вариант реализации на чистом JS. К тому же, хранить выбранные пользователем товары, мы будем не в cookie, а Local Storage (локальное хранилище). Эта технология поддерживается практически во всех современных браузерах и даже в IE8.
Буквально два слова о Local Storage для тех, кто с этим способом хранения данных на стороне клиента не знаком. Объем хранимой информации в LS по сравнению с cookie значительно выше: около 5Мб(!) против 4Кб. К тому же, в LS данные хранятся в зашифрованном виде. Однако, как и в cookie, так и в LocalStorage, мы можем записывать только строковые данные. Если нужно добавить массив или объект, то его можно предварительно преобразовать в JSON-строку (JSON.stringify(obj)), а после получения данных из LS - производим обратное преобразование (JSON.parse(json_string)). Работать с Local Storage не просто, а очень просто. Вот его основные методы:
- localStorage.setItem('key', 'value');
- Обновляет или создает новую запись с ключом "key" и строковым значением "value"
- var lsData = localStorage.getItem('key');
- Возвращает данные связанные с ключом "key" или "null", если записи с таким ключом не обнаружено
- localStorage.removeItem('key');
- Удаляет данные со связанным ключом "key"
- localStorage.clear();
- Удаляет все записи из Local Storage
Переходим к делу и для примера, создадим такую HTML-структуру для вывода товара:
<div class="item_box">
<h3 class="item_title">Samsung Galaxy S10</h3>
<p>Цена: <span class="item_price">20</span>$</p>
<button class="add_item" data-id="7">Добавить в корзину</button>
</div>
<div class="item_box">
<h3 class="item_title">LG Optimus G E100500</h3>
<p>Цена: <span class="item_price">100</span>$</p>
<button class="add_item" data-id="2">Добавить в корзину</button>
</div>
<div class="item_box">
<h3 class="item_title">Nokia 2110</h3>
<p>Цена: <span class="item_price">1000</span>$</p>
<button class="add_item" data-id="5">Добавить в корзину</button>
</div>
<button id="checkout">Оформить заказ</button>
<button id="clear_cart">Очистить корзину</button>
<div id="cart_content"></div>
Все необходимые данные, такие как наименование или цена товара, мы можем брать прямо из элементов страницы. Остается важная составляющая - ID товара, которую можно выводить в каком-нибудь атрибуте. Для таких целей, я предпочитаю атрибут data-*, который я уже упоминал в других статьях. Его-то и добавим в кнопку "Добавить в корзину" каждого из товаров.
Теперь в дело вступает JavaScript. Ничего сверхъестественного тут нет и большую часть, я прокомментирую прямо в коде:
var d = document,
itemBox = d.querySelectorAll('.item_box'), // блок каждого товара
cartCont = d.getElementById('cart_content'); // блок вывода данных корзины
// Функция кроссбраузерной установка обработчика событий
function addEvent(elem, type, handler){
if(elem.addEventListener){
elem.addEventListener(type, handler, false);
} else {
elem.attachEvent('on'+type, function(){ handler.call( elem ); });
}
return false;
}
// Получаем данные из LocalStorage
function getCartData(){
return JSON.parse(localStorage.getItem('cart'));
}
// Записываем данные в LocalStorage
function setCartData(o){
localStorage.setItem('cart', JSON.stringify(o));
return false;
}
// Добавляем товар в корзину
function addToCart(e){
this.disabled = true; // блокируем кнопку на время операции с корзиной
var cartData = getCartData() || {}, // получаем данные корзины или создаём новый объект, если данных еще нет
parentBox = this.parentNode, // родительский элемент кнопки "Добавить в корзину"
itemId = this.getAttribute('data-id'), // ID товара
itemTitle = parentBox.querySelector('.item_title').innerHTML, // название товара
itemPrice = parentBox.querySelector('.item_price').innerHTML; // стоимость товара
if(cartData.hasOwnProperty(itemId)){ // если такой товар уже в корзине, то добавляем +1 к его количеству
cartData[itemId][2] += 1;
} else { // если товара в корзине еще нет, то добавляем в объект
cartData[itemId] = [itemTitle, itemPrice, 1];
}
if(!setCartData(cartData)){ // Обновляем данные в LocalStorage
this.disabled = false; // разблокируем кнопку после обновления LS
}
return false;
}
// Устанавливаем обработчик события на каждую кнопку "Добавить в корзину"
for(var i = 0; i < itemBox.length; i++){
addEvent(itemBox[i].querySelector('.add_item'), 'click', addToCart);
}
// Открываем корзину со списком добавленных товаров
function openCart(e){
var cartData = getCartData(), // вытаскиваем все данные корзины
totalItems = '';
// если что-то в корзине уже есть, начинаем формировать данные для вывода
if(cartData !== null){
totalItems = '<table class="shopping_list"><tr><th>Наименование</th><th>Цена</th><th>Кол-во</th></tr>';
for(var items in cartData){
totalItems += '<tr>';
for(var i = 0; i < cartData[items].length; i++){
totalItems += '<td>' + cartData[items][i] + '</td>';
}
totalItems += '</tr>';
}
totalItems += '</table>';
cartCont.innerHTML = totalItems;
} else {
// если в корзине пусто, то сигнализируем об этом
cartCont.innerHTML = 'В корзине пусто!';
}
return false;
}
/* Открыть корзину */
addEvent(d.getElementById('checkout'), 'click', openCart);
/* Очистить корзину */
addEvent(d.getElementById('clear_cart'), 'click', function(e){
localStorage.removeItem('cart');
cartCont.innerHTML = 'Корзина очишена.';
});
Объект "cartData" собираем по следующей схеме: ключ к товару - его ID и данные в виде массиве [название_товара, цена_товара, количество_товара]. Если бы вы вывели такой объект средствами php, то получили бы примерно следующее:
stdClass Object ( [2] => Array ( [0] => LG Optimus G E100500 [1] => 100 [2] => 1 ) [7] => Array ( [0] => Samsung Galaxy S10 [1] => 20 [2] => 2 ) )
Это я показал, чтобы было понимание того, как потом можно работать с этими данными на стороне сервера. И плавно подошли к тому, как же эти данные отправить на сервер. В отличии от cookie, Local Storage работает только на стороне клиента. Кто-то может и записать это в минусы LS, но я не вижу проблемы, т.к. есть достаточно способов превратить минус в плюсы. Легко и непринужденно, мы можем отправить данные Ajax-запросом, а это гораздо приятней посетителю, т.к. его не перебрасывает на другую страницу, экономит время и трафик, что немаловажно, если пользователь зашёл с мобильного устройства или скорость подключения не такая высокая.
Как видите, нет ничего сложного и объем кода, без использования сторонних библиотек, получился совсем небольшим. Если кому-то нужно учитывать более старые версии Internet Explorer, то он может добавить cookie, как "fallback" к Local Storage. То есть, проверять в функциях "getCartData" и "setCartData" возможности браузера и, если он не поддерживает LS, то в качестве хранилища использовать Cookie, а остальной код останется без изменений.