Начинаем 12 часть нашего курса создания интернет-магазина на MODx Revo. В данном уроке мы с вами реализуем корзину. Если прочитать документацию к miniShop2, то мы увидим, что корзина в данном компоненте два вида корзины:
- Мини-корзина (за это отвечает сниппет msMiniCart).
- Большая корзина (ее выводит сниппет msCart).
В нашем же случае видов корзины будет 3:
- Корзина в шапке
- Выпадающая корзина
- Страница с корзиной
Начнем с большой, потому что так нам будет проще. Советую посмотреть дефолтный чанк корзины miniShop2 – tpl.msCart. Те, кто смотрел мой предыдущий курс, сразу найдут разницу – здесь мы впервые столкнемся с шаблонизатором Fenom (документация Fenom).
Для того, чтобы начать, нам необходимо интегрировать шаблон корзины (cart.html). Я надеюсь, вы помните, как мы это делали на прошлых уроках. Также необходимо создать ресурс “корзина” с данным шаблоном. У меня получилось вот так:
Дальше мы приступим к созданию чанка. В данном чанке у нас будет полностью все, что находится в элементе “section#cart-page”. Для того, чтобы посмотреть все доступные плейсхолдеры, нужно вызвать сниппет msCart с пустым параметром tpl:
<pre>[[!msCart?tpl=``]]</pre>
Теперь соединим дефолтный чанк с нашим и у нас получится следующее:
<div class="container" id="msCart"> {if !count($products)} <div class="alert alert-info" role="alert">{'ms2_cart_is_empty' | lexicon}</div> {else} <div class="col-xs-12 col-md-9 items-holder no-margin"> {foreach $products as $product} <div class="row no-margin cart-item" id="{$product.key}"> <div class="col-xs-12 col-sm-2 no-margin"> <a href="{$product.id | url}" class="thumb-holder"> {if $product.image?} <img class="lazy" src="{$product.image}" alt="{$product.pagetitle}" title="{$product.pagetitle}"/> {else} <img class="lazy" src="{'assets_url' | option}components/minishop2/img/web/ms2_small.png" srcset="{'assets_url' | option}components/minishop2/img/web/ms2_small@2x.png 2x" alt="{$product.pagetitle}" title="{$product.pagetitle}"/> {/if} </a> </div> <div class="col-xs-12 col-sm-5 "> <div class="title"> <a href="{$product.id | url}">{$product.pagetitle}</a> </div> <div class="brand">{$product['vendor.name']}</div> {if $product.options?} <div class="small"> {$product.options | join : '; '} </div> {/if} </div> <div class="col-xs-12 col-sm-3 no-margin count"> <div class="quantity"> <div class="le-quantity"> <form method="post" class="ms2_form form-inline" role="form"> <input type="hidden" name="key" value="{$product.key}"/> <a class="minus" href="#reduce"></a> <input type="number" name="count" class="counter" value="{$product.count}"/> <a class="plus" href="#add"></a> <button class="btn btn-default" type="submit" name="ms2_action" value="cart/change"> <i class="glyphicon glyphicon-refresh"></i> </button> </form> </div> </div> </div> <div class="col-xs-12 col-sm-2 no-margin"> <div class="price"> {$product.price} руб. </div> <form method="post" class="ms2_form"> <input type="hidden" name="key" value="{$product.key}"> <button class="close-btn" type="submit" name="ms2_action" value="cart/remove"> </button> </form> </div> </div> {/foreach} </div> <div class="col-xs-12 col-md-3 no-margin sidebar "> <div class="widget cart-summary"> <h1 class="border">Корзина</h1> <div class="body"> <ul id="total-price" class="tabled-data inverse-bold no-border"> <li> <label>Стоимость</label> <div class="value pull-right"> <span class="ms2_total_cost">{$total.cost}</span> руб. </div> </li> </ul> <div class="buttons-holder"> <a class="le-button big" href="checkout.html" >Оформить заказ</a> <a class="simple-link block" href="category-grid.html" >Продолжить покупки</a> </div> </div> </div> </div> {/if} </div>
Прочитать, как работает шаблонизатор и какие у него есть операторы и фишки вы можете в документации Fenom. В видео я поясню откуда я взял конкретные значения. Кроме того, мне пришлось поправить стили и скрипты шаблона. В целом, у нас сейчас все работает: изменяется количество товара в корзине и его можно удалить из корзины.
Теперь шаблон корзины у меня выглядит следующим образом:
<!DOCTYPE html> <html lang="ru"> <head> [[$meta]] </head> <body> <div class="wrapper"> [[$headerInner]] <section id="cart-page"> [[!msCart?tpl=`cartTpl`]] </section> [[$footer]] </div> [[$scripts]] </body> </html>
Неплохо не правда ли? Приступим к реализации маленькой корзины. Поступим тем же самым способом, как и с большой – будем сравнивать дефолтный чанк (tpl.msMiniCart) с нашим и будем вставлять необходимые классы и плейсхолдеры. Также я немного опередил события и добавил классы, для нашей выпадающей корзины (подробнее смотрите на видео). Не забывайте, что мини корзина у нас находится в двух чанках: header и headerInner. У меня чанк получился такой:
<a class="dropdown-toggle {$total_count > 0 ? 'full' : ''}" data-toggle="dropdown" href="[[~10]]" id="msMiniCart"> <div class="empty"> <div class="basket-item-count"> <span class="count ms2_total_count">0</span> <img src="assets/images/icon-cart.png" alt="" /> </div> <div class="total-price-basket"> <span class="lbl">Корзина:</span> <span class="total-price"> <span class="value ms2_total_cost">0</span><i class="fa fa-ruble"></i> </span> </div> </div> <div class="not_empty"> <div class="basket-item-count"> <span class="count ms2_total_count">{$total_count}</span> <img src="assets/images/icon-cart.png" alt="" /> </div> <div class="total-price-basket"> <span class="lbl">Корзина:</span> <span class="total-price"> <span class="value ms2_total_cost">{$total_cost}</span><i class="fa fa-ruble"></i> </span> </div> </div> </a>
Теперь вызываем нашу мини корзину в двух чанках шапки нашу корзину:
[[!msMiniCart?tpl=`miniCartTpl`]]
Теперь у нас есть мини корзина! Поздравляю!
И в данной части будет глава, которую достаточно много человек у меня просили в прошлом курсе – выпадающая корзина. Реализовывать будем с помощью технологии AJAX. Для начала нам нужно сделать чанк подобный большой корзине. У меня он получился следующий:
{if !count($products)} <div class="alert alert-info" role="alert">{'ms2_cart_is_empty' | lexicon}</div> {else} {foreach $products as $product} <li> <div class="basket-item"> <div class="row"> <div class="col-xs-4 col-sm-4 no-margin text-center"> <div class="thumb"> <a href="{$product.id | url}" class="thumb-holder"> {if $product.image?} <img class="lazy" src="{$product.image}" alt="{$product.pagetitle}" title="{$product.pagetitle}"/> {else} <img class="lazy" src="{'assets_url' | option}components/minishop2/img/web/ms2_small.png" srcset="{'assets_url' | option}components/minishop2/img/web/ms2_small@2x.png 2x" alt="{$product.pagetitle}" title="{$product.pagetitle}"/> {/if} </a> </div> </div> <div class="col-xs-8 col-sm-8 no-margin"> <div class="title">{$product.pagetitle}</div> <div class="price">{$product.price} <i class="fa fa-ruble"></i></div> </div> </div> <form method="post" class="ms2_form"> <input type="hidden" name="key" value="{$product.key}"> <button class="close-btn" type="submit" name="ms2_action" value="cart/remove"> </button> </form> </div> </li> {/foreach} <li class="checkout"> <div class="basket-item"> <div class="row"> <div class="col-xs-12 col-sm-6"> <a href="[[~10]]" class="le-button inverse">Корзина</a> </div> <div class="col-xs-12 col-sm-6"> <a href="checkout.html" class="le-button">Оформить заказ</a> </div> </div> </div> </li> {/if}
Заметили, что он получается подобный крупной корзине? Теперь на нужно создать несколько ресурсов, к которым мы будем обращаться по ajax. Обычно для таких ресурсов я создаю контейнер “технические ресурсы”/”ajax” и создаем ресурс с пустым шаблоном, отключаем текстовый редактор на вкладке настройки.
В содержимом ресурса вызываем уже знакомы сниппет:
[[!msCart?tpl=`toggleCartTpl` &sortdir=`DESC`]]
Только мы сменили сортировку, последние добавленные товары будут первыми. И нам осталось написать скрипт JS, который мы разместим в чанке “scripts”:
<script> $(document).on('click', '#msMiniCart', function(e) { e.preventDefault(); $.ajax({ type: "POST", url: '[[~13]]', data: {parent: '[[*id]]'}, success: function(data) { if (data){ $('.basket .ajax-data').html(data); }else{ miniShop2.Message.error('Что-то пошло не так, попробуйте позже!'); } } }); }); </script>
Ура! У нас работает всплывающая корзина! Делается все очень просто, не правда ли? На этом мы закончили реализацию наших корзин. Осталось дело за малым – настроить стили, а то они немного подслетели. До следующих уроков!