Товар
Назначение атрибутов
Пример разметки товара
<form action="{{ cart_url }}" method="post" data-product-id="{{ product.id }}">
<div class="product__sku">
<span data-product-card-sku='{
"skuLabel": "Артикул."
}'
></span>
</div>
<span data-product-card-available='{
"availableText": "Товар в наличии",
"notAvailableText": "Нет в наличии"
}'
>
</span>
<div data-product-card-old-price></div>
<div data-product-card-price></div>
{% if product.show_variants? %}
<select name="variant_id" data-product-variants='{"default": "option-radio"}'>
{% for variant in product.variants %}
<option value="{{ variant.id }}">{{ variant.title | escape }}</option>
{% endfor %}
</select>
{% else %}
<input type="hidden" name="variant_id" value="{{product.variants.first.id}}" >
{% endif %}
<input type="text" name="comment" value="">
<div data-quantity data-min="1">
<input type="text" name="quantity" value="1" />
<span data-quantity-change="-1">-</span>
<span data-quantity-change="1">+</span>
</div>
<button type="submit" data-item-add>
Добавить в корзину
</button>
{% if account.quick_checkout.enabled %}
<button data-quick-checkout="[data-product-id='{{ product.id }}']">
Купить в 1 клик
</button>
{% endif %}
</form>
Атрибуты корневого элемента
data-product-id
Обязательный атрибут для инициализации товара, принимает ID товара
<form data-product-id="{{ product.id }}" action="{{ cart_url }}" method="post">
<!-- Код формы -->
</form>
data-product-without-cache
Отключить кэширование информации о товаре
<form data-product-without-cache data-product-id="{{ product.id }}" action="{{ cart_url }}" method="post" >
<!-- Код формы -->
</form>
data-product-json
Позволяет передать данные о товаре через Liquid. Это может ускорить отображение селектора вариантов.
<form data-product-id="{{ product.id }}" data-product-json="{{ product|json|escape }}" action="{{ cart_url }}" method="post">
<!-- Код формы -->
</form>
data-product-without-many-variants
Если в карточке товара отсутствует селектор выбора варианта, то рекомендуется указать данный атрибут со значение true
. Тогда при запросе на сервер товар будет получен только с первым вариантом. Это может значительно ускорить загрузку страницы. Рекомендуется использовать в превью товаров, например, на страницах категорий.
Info
Если задан атрибут data-product-json
, то все данные о товаре, включая варианты, будут получены в виде JSON вместе с HTML-кодом страницы, а не запросом к серверу.
<form data-product-id="{{ product.id }}" data-product-without-many-variants="true" action="{{ cart_url }}" method="post">
<!-- Код формы -->
</form>
data-set-config
Передать настройки товара через data-атрибут
<form data-set-config='{"decimal": {"kgm": 1}}' data-product-id="{{ product.id }}" action="{{ cart_url }}" method="post">
<!-- Код формы -->
</form>
Атрибуты вложенных элементов
data-product-variants
Каждый вариант товара состоит из свойств и их значений, например: "Цвет: Красный, Размер: 42", "Цвет: Синий, Размер: 38".
Данный атрибут позволяет указать вид отображения значений свойств варианта товара в зависимости от названия свойства.
Доступные виды:
- option-select
- option-select-image
- option-span
- option-radio
- option-preview
- option-preview-text
- option-default (option-select)
Разметка каждого вида хранится внутри библиотеки в виде lodash-шаблонов. Посмотреть код шаблонов можно здесь
В следующем примере в качестве вида по умолчанию установлен option-select
: для свойства "Цвет" - option-preview
, для свойства "Размер" - option-span
.
{% if product.show_variants? %}
<select name="variant_id" data-product-variants='{
"default": "option-select",
"Цвет": "option-preview",
"Размер": "option-span"
}'>
{% for variant in product.variants %}
<option value="{{ variant.id }}">{{ variant.title | escape }}</option>
{% endfor %}
</select>
{% else %}
<input type="hidden" name="variant_id" value="{{product.variants.first.id}}" >
{% endif %}
Можно ли написать свой шаблон для отображения свойств?
Можно. Для этого в разметку нужно добавить тег script с data-атрибутом data-template-id
, в качестве значения которого должен быть указан ID шаблона.
<script type="text/template" data-template-id="custom-span">
<div class="<%= classes.option %> is-span">
<label class="<%= classes.label %>"><%= title %></label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<button class="<%= value.classes.all %> is-span"
<%= value.controls %>
<%= value.state %>
>
<%= value.title %>
</button>
<% }) %>
</div>
</div>
</script>
После чего можно указать свой шаблон по умолчанию.
{% if product.show_variants? %}
<select name="variant_id" data-product-variants='{
"default": "custom-span"
}'>
{% for variant in product.variants %}
<option value="{{ variant.id }}">{{ variant.title | escape }}</option>
{% endfor %}
</select>
{% else %}
<input type="hidden" name="variant_id" value="{{product.variants.first.id}}" >
{% endif %}
data-quantity
Обязательный атрибут для обёртки кнопок изменения количества и инпута quantity
Для установки минимального значения в input количества товара передайте атрибут data-min с нужным значением
<div data-quantity>
<button type="button" data-quantity-change="-1">-</button>
<input type="text" value="1" name="quantity"/>
<button type="button" data-quantity-change="1">+</button>
</div>
data-quantity-change
Атрибут для кнопок изменения количества +/-, принимает число
data-item-add
Добавление товара в корзину
data-add-cart-counter
Компонент, который совмещает в себе функционал добавления товара в корзину, изменения количества, отображения счётчика и возможность удаления из корзины. Он используется в виджетах карточек товаров в шаблонах 4 поколения.
В значении атрибута нужно указать шаг изменения количества товара: data-add-cart-counter='{"step": "1"}'
Вложенные элементы:
- data-add-cart-counter-btn — кнопка добавления товара в корзину
- data-add-cart-counter-minus — кнопка уменьшения количества или удаления из корзины
- data-add-cart-counter-count — счётчик количества товара в корзине
- data-add-cart-counter-plus — кнопка увеличения количества
События:
unchange_quantity:insales:ui_add-cart-counter - срабатывает если достигнуто максимальное количество товара в корзине
EventBus.subscribe('unchange_quantity:insales:ui_add-cart-counter', data => {
console.log(data);
})
Пример кода:
Всё что вам необходимо сделать для использования — это задать стили для элементов и скрывать/показывать нужные кнопки, если у корневого элемента есть класс is-add-cart
.
<div class="add-cart-counter" data-add-cart-counter='{"step": "1"}'>
<button type="button" class="add-cart-counter__btn" data-add-cart-counter-btn>
Add to cart
</button>
<div class="add-cart-counter__controls">
<button data-add-cart-counter-minus class="add-cart-counter__controls-btn" type="button">-</button>
<a href="{{cart_url}}" class="add-cart-counter__detail">
<span class="add-cart-counter__detail-text">{{messages.btn_buy_active_text}} <span data-add-cart-counter-count></span> {{ product.unit }}</span>
</a>
<button data-add-cart-counter-plus class="add-cart-counter__controls-btn" type="button">+</button>
</div>
</div>
data-product-card-preorder
Атрибут предназначен для кнопки вызова формы предзаказа. При загрузке страницы кнопка получает атрибуты data-preorder-product-name
и data-preorder-variant
, которые содержат название товара и название выбранного варианта.
Значение атрибута data-preorder-variant
обновляется при выборе варианта товара.
Если подписаться на EventBus-событие show-preorder:insales:ui_product
, то при нажатии на кнопку вы сможете получать название товара и выбранного варианта, чтобы использовать их в форме предзаказа.
<button data-product-card-preorder type="button">{{messages.pre_order}}</button>
data-quick-checkout
Форма заказа в один клик
<button data-quick-checkout></button>
В качестве значения можно передать ID конкретного товара. Однако, если в корзину уже добавлены другие товары, то они тоже попадут в заказ.
<button data-quick-checkout="[data-product-id='{{ product.id }}']"></button>
data-product-card-price
Цена продажи варианта товара
<span data-product-card-price></span>
data-product-card-price-from-cart
Цена продажи варианта товара с учётом типов цен
<span data-product-card-price-from-cart></span>
data-product-card-old-price
Старая цена варианта товара
<span data-product-card-old-price></span>
data-product-card-sku
Получение артикула варианта товара. В качестве значения можно передать label.
<span data-product-card-sku='{"skuLabel": "{{messages.sku_label}}"}'></span>
data-product-card-available
Наличие варианта товара.
В качестве значения можно передать объект со статусами.
<span data-product-card-available='{"availableText": "Available", "notAvailableText": "Not available"}'>
name="comment"
Комментарий к позиции заказа. Для корректной работы необходимо, чтобы комментарии к заказам были включены в админ-панели, в разделе "Настройки" > "Оформление заказа"
<input type="text" name="comment" value="">
Селектор модификаций
Привязка шаблона модификации к опции
В методе
setConfig
нужно передать объект options в видеимя опции: ID шаблона
Products.setConfig({
options: {
'Цвет': 'option-image',
'Размер': 'option-radio',
'Материал': 'option-select',
'Жесткий диск': 'option-span'
}
});
Пример шаблона
<script type="text/template" data-template-id="option-span">
<div class="<%= classes.option %> is-span">
<label class="<%= classes.label %>"><%= title %></label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<button class="<%= value.classes.all %> is-span"
<%= value.controls %>
<%= value.state %>
>
<%= value.title %>
</button>
<% }) %>
</div>
</div>
</script>
Передать изображения для шаблона селектора модификаций
Ссылки формируются в виде
значение свойства + .png | file_url
<script>
{% comment %}
создание объекта с картинками из файлов для collection
{% endcomment %}
if (!fileUrl) {
var fileUrl = {}
}
{% assign option_title = 'Цвет' %}
{% assign collection_handle = 'all' %}
{% assign image_format = '.png' %}
{% for option_name in collections[collection_handle].options %}
{% if option_name.title == option_title %}
{% for option_value in option_name.values %}
{% capture fileName %}{{option_value.title | replace: ' ', '_' }}{{image_format}}{% endcapture %}
{% assign fileURL = fileName | file_url %}
{% if fileURL %}
fileUrl['{{ option_value.title | downcase }}'] = '{{ fileURL }}';
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</script>
<script>
{% comment %}
создание объекта с картинками из файлов для product
{% endcomment %}
if (!fileUrl) {
var fileUrl = {}
}
{% assign option_title = 'цвет' %}
{% assign image_format = '.png' %}
{% for option in product.options %}
{% assign option-title = option.title | downcase %}
{% if option-title == option_title %}
{% for value in option.values %}
{% capture fileName %}{{value.title | replace: ' ', '_'}}{{image_format}}{% endcapture %}
{% assign fileURL = fileName | downcase | file_url %}
{% if fileURL %}
fileUrl['{{ value.title | downcase }}'] = encodeURI('{{ fileURL }}');
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</script>
<script>
Products.setConfig({
fileUrl: (typeof fileUrl == 'undefined') ? {} : fileUrl
});
</script>
Шаблоны для селектора модификаций
select
<script type="text/template" data-template-id="option-select">
<div class="<%= classes.option %> is-select">
<label class="<%= classes.label %>"><%= title %></label>
<select class="<%= classes.values %>" data-option-bind="<%= option.id %>">
<% _.forEach(values, function (value){ %>
<option
<%= value.controls %>
<%= value.state %>
>
<%= value.title %>
</option>
<% }) %>
</select>
</div>
</script>
select-image
<script type="text/template" data-template-id="option-select-image">
<div class="<%= classes.option %> <%= _.find(values, 'image_url') ? 'is-system-color' : '' %> is-select">
<% if (_.find(values, 'image_url')) { %>
<label class="<%= classes.label %>">
<%= title %>
</label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<label class="<%= value.classes.all %> is-radio">
<input class="<%= value.classes.state %>" type="radio" name="<%= handle %>" <%= value.state %>
<%= value.controls %>
>
<span class="option-value-system-color <%= value.image_url ? 'with-image-color' : 'without-image-color' %>">
<% if (value.image_url) { %>
<img width="40px" src="<%= value.image_url %>" alt="<%= value.titleWithoutQuotes %>"
title="<%= value.titleWithoutQuotes %>">
<% } else { %>
<%= value.title %>
<% } %>
</span>
</label>
<% }) %>
</div>
<% } else { %>
<label class="<%= classes.label %>"><%= title %></label>
<select class="<%= classes.values %>" data-option-bind="<%= option.id %>">
<% _.forEach(values, function (value){ %>
<option
<%= value.controls %>
<%= value.state %>
>
<%= value.title %>
</option>
<% }) %>
</select>
<% } %>
</div>
</script>
span
<script type="text/template" data-template-id="option-span">
<div class="<%= classes.option %> is-span">
<label class="<%= classes.label %>"><%= title %></label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<button class="<%= value.classes.all %> is-span"
<%= value.controls %>
<%= value.state %>
>
<%= value.title %>
</button>
<% }) %>
</div>
</div>
</script>
radio
<script type="text/template" data-template-id="option-radio">
<div class="<%= classes.option %> is-radio">
<label class="<%= classes.label %>"><%= title %></label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<label class="<%= value.classes.all %> is-radio">
<input class="<%= value.classes.state %>"
type="radio"
name="<%= handle %>"
<%= value.state %>
<%= value.controls %>
>
<span><%= value.title %></span>
</label>
<% }) %>
</div>
</div>
</script>
preview
<script type="text/template" data-template-id="option-preview">
<div class="<%= classes.option %> option-<%= option.handle %>" is-span is-preview">
<label class="<%= classes.label %>"><%= title %></label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<button class="<%= value.classes.all %> is-span is-preview"
<%= value.controls %>
<%= value.state %>
>
<% if(value.imageFromVariant){ %>
<img width="40px" src="<%= value.imageFromVariant.medium_url %>" alt="<%= value.titleWithoutQuotes %>" title="<%= value.titleWithoutQuotes %>">
<% }else{ %>
<span><%= value.title %></span>
<% } %>
</button>
<% }) %>
</div>
</div>
</script>
preview-text
<script type="text/template" data-template-id="option-preview-text">
<div class="<%= classes.option %> is-span is-preview-text">
<label class="<%= classes.label %>">
<%= title %>
</label>
<div class="<%= classes.values %>">
<% _.forEach(values, function (value){ %>
<button class="<%= value.classes.all %> is-span is-preview-text <%= (value.variant.image_id ? 'is-img' : 'is-text') %>" <%= value.controls %>
<%= value.state %>
>
<% if(value.imageFromVariant && value.variant.image_id){ %>
<img width="40px" src="<%= value.imageFromVariant.medium_url %>" alt="<%= value.titleWithoutQuotes %>"
title="<%= value.titleWithoutQuotes %>">
<% }else{ %>
<span>
<%= value.title %>
</span>
<% } %>
</button>
<% }) %>
</div>
</div>
</script>
Методы класса Products
get
Получить объект с информацией о конкретном товаре
/**
* @param {number} id id товара
* @return {Deferred}
*/
Products.get(123456)
.done(function (onDone) { console.log('onDone', onDone) })
.fail(function (onFail) { console.log('onFail', onFail) });
getList
Получение списка товаров
/**
* @param {Array} idList - массив, состоящий из id товаров
* @return {Deferred}
*/
Products.getList([123456, 123455, 1234454, 123458])
.done(function (onDone) { console.log('onDone', onDone) })
.fail(function (onFail) { console.log('onFail', onFail) });
Info
Все полученные товары кэшируются в local storage. Это означает, что при отправке новых запросов товары, которые уже были получены с сервера в предыдущих запросах, будут доставаться из кэша. Это работает только в рамках одной сессии. То есть, если перезагрузить страницу, то товары снова будут получены запросом. Если по каким-то причинам вам нужно, чтобы этого не происходило, то необходимо вторым аргументом передать объект со свойством no_cache
и значением true
.
Warning
В одном запросе можно получить не более 700 товаров. Если превысить этот лимит, то перед отправкой запроса на сервер массив будет обрезан.
setConfig
Обновление настроек
Параметры
Property | Default | Назначение |
---|---|---|
options | { 'default': 'option-default' } |
Через данный объект задаются шаблоны для вывода свойств варианта |
fileUrl | Пустой объект | Объект для хранения картинок из раздела «Файлы» |
decimal | Пустой объект | Количество символов после запятой для единиц измерения |
filtered | true | Если значение true, то недоступные опции не выводятся в шаблон. |
disableHideItem | false | Показывает отсутствующие в наличии варианты товаров, даже если в админ-панели их отображение отключено |
selectUnavailable | true | Разрешить выбирать недоступный вариант (актуально если filtered: false ) |
allowUnavailable | false | Разрешить выбирать первым недоступный вариант |
showVariants | true | При значении false рендер вариантов не производится |
initOption | true | Отмечать активные свойства при инициализации? |
useMax | false | Использовать максимальное количество? Если значение true, в quantity невозможно указать количество больше, чем доступно на складе |
Warning
Вызов данного метода стоит оставлять в глобальной области видимости. Если запустить метод внутри $(document).ready(function() {})
, результат может быть непредсказуем.
Products.setConfig({
showVariants: true,
hideSelect: true,
initOption: true,
fileUrl: (typeof fileUrl == 'undefined') ? {} : fileUrl,
filtered: true,
selectUnavailable: true
})
getInstance
Получаем экземпляр класса ProductInstance из jQuery DOM element
/**
* @param {jQuery DOM element} $node jQuery DOM element например $('.product-cart-control')
*/
Products.getInstance($('.product-cart-control'))
.done(function (onDone) { console.log('onDone', onDone) })
.fail(function (onFail) { console.log('onFail', onFail) });
initInstance
Инициализация формы товара
/**
* @param {jQuery DOM element} $node jQuery DOM element например $('.product-cart-control')
*/
Products.initInstance($('.product-cart-control'))
.done(function (onDone) { console.log('onDone', onDone) })
.fail(function (onFail) { console.log('onFail', onFail) });
getRecentlyViewed
Возвращает массив с ID просмотренных товаров
Products.getRecentlyViewed()
.done(function (onDone) { console.log('onDone', onDone) })
.fail(function (onFail) { console.log('onFail', onFail) });
События
Событие | Описание |
---|---|
init_instance:insales:product | Срабатывает после инициализации оберток [data-product-id] с инициализацией всех дочерних элементов |
before:insales:product | Срабатывает перед любым взаимодействием с компонентом товара |
always:insales:product | Срабатывает после любого взаимодействия с компонентом товара |
change_quantity:insales:product | Обновление количества товара в инпуте quantity |
unchange_quantity:insales:product | Если введено кол-во больше доступного |
overload:quantity:insales:product | Событие срабатывает, когда с помощью +/- накликали до максимального значения quantity (Работает, если вы используете параметр useMax) |
max:quantity:insales:product | Срабатывает всегда, когда в инпуте установлено максимальное кол-во, даже при загрузке страницы (Работает, если вы используете параметр useMax) |
change_variant:insales:product | Срабатывает при выборе варианта товара |
update_variant:insales:product | Обновление варианта товара |
Пример подписки на событие
EventBus.subscribe('change_quantity:insales:product', function (data) {
console.log('Изменено количество товара в счётчике', data);
});