У Битрикса есть хороший стандартный компонент и шаблон корзины
Можно его в свое пространство имен скопировать, убрать лишнее (например, подарки), навесить свои стили, добавить функционал
Если есть суперсложная логика в корзине (например, Вы продаете лицензии или страховки), то удобно делать корзину на bx.vue
Реализация корзины на BX.Vue
компонент test:basket
class.php
template.php
script.js
вызываем событие (например, при добавлении товара в корзину)
и наша корзина обновится
страница, где корзина /cart/index.php
вызываем компонент
вот так выглядит (страшно, но зато элементарно по коду все)

Директивы vue
v-show
отображение элемента в зависимости от переданного значения
showH1 - true/false
элемент всегда в DOM, менятся display
v-if
как v-show, но элемента не будет в DOM
showH1 - true/false
v-else
иначе
после v-if
но надежнее 2 v-if
v-else-if
v-bind
для вывода динамических данных внутри html атрибута
например, href будет меняться от myUrl
v-model
как v-bind, но связка двухсторонняя
например, при изменении value инпута меняется someText
v-on
вешаем событие
myMethod описать в methods:
v-for
цикл
v-html
для вставки html
переменная myHtml будет версткой
- компонент bitrix:sale.basket.basket
- шаблон bootstrap_v4
- параметрыкомпонента
Можно его в свое пространство имен скопировать, убрать лишнее (например, подарки), навесить свои стили, добавить функционал
|
Если есть суперсложная логика в корзине (например, Вы продаете лицензии или страховки), то удобно делать корзину на bx.vue
Реализация корзины на BX.Vue
| Ниже пример очень простой корзины и простой верстки для понимания BX.Vue |
- test/basket/class.php
- test/basket/templates/.default/template.php
- test/basket/templates/.default/script.js
class.php
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
use Bitrix\Main\Engine\Contract\Controllerable;
use Bitrix\Main\Engine\ActionFilter\Csrf;
use Bitrix\Main\Engine\ActionFilter\HttpMethod;
use Bitrix\Main\Loader;
use Bitrix\Sale\Basket;
class CMyBasket extends CBitrixComponent implements Controllerable{
public function configureActions()
{
return [
'GetBasket' => [ // Ajax-метод
'prefilters' => [],
'postfilters' => []
],
'UpdateItem'=> [ // Ajax-метод
'prefilters' => [],
'postfilters' => []
],
'DeleteItem'=> [ // Ajax-метод
'prefilters' => [],
'postfilters' => []
],
];
}
public function __construct(CBitrixComponent $component = null)
{
parent::__construct($component);
Loader::includeModule("sale"); //сразу подключаем модуль sale
}
public function executeComponent(){
$this->GetBasket();
$this->includeComponentTemplate();
}
public function GetBasket(){ //получение товаров в корзине
$fUser = Fuser::getId();
$basket = Basket::loadItemsForFUser($fUser, SITE_ID);
$this->arResult = [
"totalPrice" => $basket->getPrice(),
"items" => [],
];
$items = $basket->getBasketItems();
foreach ($items as $item) {
$this->arResult["items"][] = [
"id" => $item->getID(),
"title" => $item->getField("NAME"),
"priceItem"=> $item->getPrice(),
"price" => ceil($item->getPrice() * $item->getField("QUANTITY")*100)/100,
"quantity" => intval($item->getField("QUANTITY")),
];
}
}
public function GetBasketAction($sessid){
$this->GetBasket();
return $this->arResult;
}
public function UpdateItemAction($id,$q,$sessid){
if (!check_bitrix_sessid()) {
throw new \Exception("SESSION_EXPIRED", 1);
}
$fUser = Fuser::getId();
$basket = Basket::loadItemsForFUser($fUser, SITE_ID);
$items = $basket->getBasketItems();
foreach ($items as $item) {
if($item->getID() == $id){
$item->setField('QUANTITY', $q);
$item->save();
break;
}
}
return true;
}
public function DeleteItemAction($id,$sessid){
if (!check_bitrix_sessid()) {
throw new \Exception("SESSION_EXPIRED", 1);
}
$fUser = Fuser::getId();
$basket = Basket::loadItemsForFUser($fUser, SITE_ID);
$items = $basket->getBasketItems();
foreach ($items as $item) {
if($item->getID() == $id){
$item->delete();
$basket->save();
break;
}
}
return true;
}
} |
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
\Bitrix\Main\UI\Extension::load("ui.vue");
\Bitrix\Main\UI\Extension::load("ui.vue.vuex");
?>
<div id="basket"></div>
<script>
var store = BX.Vuex.store({
state: {
loaded: false,
items: <?= CUtil::PhpToJSObject($arResult['items']) ?>,
totalPrice: <?=$arResult['totalPrice']?>
},
actions: {
},
mutations: { //мутаторы, при их вызове будет перерисовываться корзина
setLoad(state, flag) {
state.loaded = flag;
},
setbasketItems(state, items) {
state.items = items;
},
setTotalprice(state, totalPrice) {
state.totalPrice = totalPrice;
}
}
})
BX.Vue.create({
el: '#basket',
store: store,
template: `<basket/>`,
})
</script> |
;(function (window) {
"use strict"
const BX = window.BX;
BX.Vue.component("basket", {
props:{},
data(){
return { //данные для первоначальной отрисовки
items: this.$store.state.items,
loaded: false,
totalPrice: this.$store.state.totalPrice,
}
},
created() {
BX.Vue.event.$on("updateBasket", this.getBasket); //подписываемся на событие updateBasket (если это корзина в шапке и надо обновлять при добавлении нового товара в корзину)
},
updated: function () {
//при изменении обработчик
},
beforeDestroy() {
//обработчик перед destroy
},
methods: {
getBasket: function () {
store.commit("setLoad", true);
var request = BX.ajax.runComponentAction("test:basket", "GetBasket", { //запустится метод GetBasketAction из class.php
mode: "class",
data: {
sessid: BX.message("bitrix_sessid"),
},
})
request.catch(function (response) {
console.log(response);
store.commit("setLoad", false);
})
request.then(function (response) {
if (response.status == "success") {
store.commit("setbasketItems", response.data.items);
store.commit("setTotalprice", response.data.totalPrice);
store.commit("setLoad", false);
}
})
},
remove: function (id) {
store.commit("setLoad", true);
var t = this;
var request = BX.ajax.runComponentAction("test:basket", "DeleteItem", { //запустится метод DeleteItemAction из class.php
mode: "class",
data: {
id: id,
sessid: BX.message("bitrix_sessid"),
},
})
request.catch(function (response) {
console.log(response);
store.commit("setLoad", false);
});
request.then(function (response) {
if (response.status == "success") {
t.getBasket();
}
});
},
minus: function (id,q) {
if(q==1){//удаляем
this.remove(id);
}
else{
q = q -1;
}
this.update(id,q);
},
plus: function (id,q) {
q = q*1+1;
this.update(id,q);
},
update: function (id,q) {
var t = this;
store.commit("setLoad", true);
var request = BX.ajax.runComponentAction("test:basket", "UpdateItem", { //запустится метод UpdateItemAction из class.php
mode: "class",
data: {
id: id,
q: q,
sessid: BX.message("bitrix_sessid"),
},
});
request.catch(function (response) {
console.log(response);
store.commit("setLoad", false);
});
request.then(function (response) {
if (response.status == "success") {
t.getBasket();
}
});
},
save: function () {},
},
computed: {},
template: `
<div>
<h1>Корзина</h1>
<div v-if="this.$store.state.loaded">
ожидайте...
</div>
<div v-if="!this.$store.state.loaded">
<div v-if="this.$store.state.items.length==0">
корзина пустая
</div>
<div v-else>
<div v-for="item in this.$store.state.items" :key="item.id">
<b>{{item.title}}</b> {{item.priceItem}} руб/шт.
<button v-on:click="minus(item.id,item.quantity)">-</button>
{{item.quantity}} шт.
<button v-on:click="plus(item.id,item.quantity)">+</button>
=> {{item.price}} руб.
<button v-on:click="remove(item.id)">Удалить</button>
</div>
<br><br>
<div>Всего цена: {{this.$store.state.totalPrice}} руб.</div>
<div><a href="/personal/order/make/">Оформить заказ</a></div>
</div>
</div>
</div>
`,
})
})(window); |
вызываем событие (например, при добавлении товара в корзину)
и наша корзина обновится
BX.Vue.event.$emit("updateBasket", {}); |
вызываем компонент
<?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
$APPLICATION->SetTitle("Корзина");?>
<?$APPLICATION->IncludeComponent("test:basket", "", []);?>
<?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");?> |
вот так выглядит (страшно, но зато элементарно по коду все)

Директивы vue
v-show
отображение элемента в зависимости от переданного значения
showH1 - true/false
элемент всегда в DOM, менятся display
<h1 v-show="showH1">Заголовок</h1> |
как v-show, но элемента не будет в DOM
showH1 - true/false
<h1 v-if="showH1">Заголовок</h1> |
иначе
после v-if
<h1 v-if="showH1">Заголовок 1</h1> <h1 v-else>Заголовок 2</h1> |
<h1 v-if="showH1">Заголовок 1</h1> <h1 v-if="!showH1">Заголовок 2</h1> |
<h1 v-if="showH1">Заголовок 1</h1> <h1 v-else-if="showH2">Заголовок 2</h1> <h1 v-else>Заголовок 3</h1> |
v-bind
для вывода динамических данных внутри html атрибута
например, href будет меняться от myUrl
<а v-bind:href="myUrl">Ссылка</а> |
v-model
как v-bind, но связка двухсторонняя
например, при изменении value инпута меняется someText
<input type="text" v-model="someText"> |
v-on
вешаем событие
myMethod описать в methods:
<button v-on:click="myMethod">Click me</button> |
с версии vue 2.4.0 доступна возможность навесить сразу несколько событий на элемент.
<button v-on="{ mousedown: myMethod1, mouseup: myMethod2 }">Click me</button> |
v-for
цикл
<div v-for="item in this.$store.state.items" :key="item.id">
{{item.title}} - {{item.id}}
</div> |
v-html
для вставки html
переменная myHtml будет версткой
<div v-html="myHtml"></div> |