Реактивный компонент сравнения товаров на Vue.js для Битрикс
Типичная ситуация: пользователь добавляет товар в сравнение, страница перезагружается, счётчик меняется. Через три клика он уходит на маркетплейс. Стандартный компонент сравнения 1С-Битрикс (bitrix:catalog.compare.buy и bitrix:catalog.compare.result) работал приемлемо много лет назад, но сегодня UX-ожидания кардинально изменились. Мы предлагаем заменить его на современное Vue.js-решение: добавление в сравнение мгновенно, счётчик в шапке обновляется без перезагрузки, таблица умеет скрывать одинаковые характеристики. Компонент разрабатываем под ключ, с адаптивом и поддержкой.
Почему стоит заменить стандартное сравнение на Vue.js?
Стандартный компонент использует сессию PHP для хранения списка — это означает перезагрузку при каждом действии. Vue.js-версия работает полностью на фронтенде: состояние хранится в Pinia-store, синхронизируется с localStorage для гостей и с сервером для авторизованных. Это даёт скорость, отзывчивость и сохранение выбора между сессиями. В результате время добавления товара сокращается с 1-2 секунд до 50 мс, а конверсия в корзину вырастает на 15–25%.
Как работает компонент?
Хранение списка сравнения
Стандартный Битрикс хранит сравнение в сессии PHP. Мы используем localStorage с синхронизацией на сервер для авторизованных пользователей — так список сохраняется между сессиями и устройствами.
// stores/compareStore.ts (Pinia)
export const useCompareStore = defineStore('compare', {
state: () => ({
items: [] as number[], // product IDs
}),
actions: {
async add(productId: number) {
if (this.items.includes(productId)) return
if (this.items.length >= 4) {
alert('Можно сравнивать до 4 товаров одновременно')
return
}
this.items.push(productId)
localStorage.setItem('compare_items', JSON.stringify(this.items))
// Синхронизация с сервером для авторизованных
if (isLoggedIn()) {
await fetch('/local/api/compare/add/', {
method: 'POST',
body: JSON.stringify({ product_id: productId }),
})
}
},
remove(productId: number) {
this.items = this.items.filter(id => id !== productId)
localStorage.setItem('compare_items', JSON.stringify(this.items))
},
isInCompare: (state) => (productId: number) => state.items.includes(productId),
},
getters: {
count: (state) => state.items.length,
},
})
При инициализации приложения список загружается из localStorage (для гостей) или из API (для авторизованных, с мержем между устройствами).
Кнопка «Сравнить» на карточке товара
<!-- CompareButton.vue -->
<template>
<button
:class="['compare-btn', { 'compare-btn--active': isAdded }]"
@click="toggle"
:title="isAdded ? 'Убрать из сравнения' : 'Добавить к сравнению'"
>
<IconScale :filled="isAdded" />
<span>{{ isAdded ? 'В сравнении' : 'Сравнить' }}</span>
</button>
</template>
<script setup lang="ts">
const props = defineProps<{ productId: number }>()
const store = useCompareStore()
const isAdded = computed(() => store.isInCompare(props.productId))
function toggle() {
isAdded.value ? store.remove(props.productId) : store.add(props.productId)
}
</script>
Кнопка монтируется на каждой карточке товара через data-атрибут.
Счётчик в шапке сайта
<!-- CompareCounter.vue (монтируется в header) -->
<template>
<a href="/compare/" class="header-compare">
<IconScale />
<span class="badge" v-if="count > 0">{{ count }}</span>
</a>
</template>
<script setup lang="ts">
const store = useCompareStore()
const count = computed(() => store.count)
</script>
Счётчик реактивно обновляется через Pinia — никакого глобального EventBus.
Таблица сравнения с дифф-фильтром
Самая сложная часть — таблица. Данные загружаются с сервера по списку ID, затем на фронте строится карта различий. Кнопка «Показать только различия» скрывает строки с одинаковыми значениями.
<!-- CompareTable.vue (упрощённо) -->
<template>
<table class="compare-table">
<thead>
<tr>
<th>Характеристика</th>
<th v-for="p in products" :key="p.id">
<ProductCard :product="p" @remove="store.remove(p.id)" />
</th>
</tr>
</thead>
<tbody>
<tr
v-for="spec in visibleSpecs"
:key="spec"
:class="{ 'row--different': diffMap[spec] }"
>
<td class="spec-name">{{ specLabels[spec] }}</td>
<td v-for="p in products" :key="p.id">{{ p.specs[spec] ?? '—' }}</td>
</tr>
</tbody>
</table>
</template>
<script setup lang="ts">
const showOnlyDiff = ref(false)
const visibleSpecs = computed(() =>
showOnlyDiff.value
? Object.keys(diffMap.value).filter(k => diffMap.value[k])
: Object.keys(diffMap.value)
)
</script>
На мобильных первая колонка фиксируется через CSS Grid с position: sticky.
Как интегрировать компонент в шаблон?
Интеграция состоит из трёх шагов:
- Разместить точки монтирования в PHP-шаблонах:
data-compare-btnдля кнопок на карточках,data-compare-counterдля счётчика в шапке,data-compare-tableдля страницы сравнения. - Подключить собранный бандл Vue.js через
RegisterModuleв эпилог шаблона. - Настроить API-контроллер для получения данных товаров по списку ID (свойства с
COMPARE = 'Y').
Кейс: рост конверсии на 20% после внедрения
Один из наших клиентов — интернет-магазин с каталогом ~5 000 товаров — столкнулся с низкой конверсией на странице сравнения (всего 2% переходов в корзину). Стандартный компонент работал медленно: каждое действие вызывало перезагрузку. После внедрения Vue.js-компонента скорость выборки сократилась на 70%, а доля пользователей, добавивших товар в корзину со страницы сравнения, выросла до 22%. Ключевой фишкой стала кнопка «Показать только различия» — клиенты быстрее находили отличия и принимали решение.
Сравнение подходов: стандартный vs Vue.js
| Параметр | Стандартный компонент | Vue.js-компонент |
|---|---|---|
| Время добавления товара | ~1-2 сек (с перезагрузкой) | ~50 мс (без перезагрузки) |
| Сохранение списка | Только сессия PHP | localStorage + серверная синхронизация |
| Адаптив на мобильных | Ограниченный | CSS Grid со sticky-колонкой |
| Фильтр различий | Нет | Есть |
| Конверсия в корзину | ~2% | ~22% (по данным кейса) |
Что входит в работу
Мы отдаём готовый компонент, который включает:
- Исходный код на Vue.js 3 + Pinia + TypeScript.
- PHP-контроллер для API сравнения (опционально).
- Инструкцию по интеграции в шаблон 1С-Битрикс.
- Доступ к репозиторию с историей изменений.
- Консультационную поддержку в течение 2 недель после сдачи.
Процесс работы и сроки
| Этап | Длительность | Результат |
|---|---|---|
| Аналитика и проектирование | 1–2 дня | ТЗ, макет интеграции |
| Разработка компонента | 5–10 дней | Рабочий прототип |
| Интеграция и тестирование | 2–3 дня | Готовый функционал на стенде |
| Деплой и документирование | 1 день | Передача кода и инструкций |
Ориентировочные сроки: от 1 до 3 недель в зависимости от сложности. Свяжитесь с нами — мы оценим ваш проект бесплатно.
Наш опыт
Мы занимаемся Битрикс-разработкой более 5 лет и реализовали свыше 50 проектов, включая кастомные компоненты для интернет-магазинов. Знаем все подводные камни интеграции Vue.js с 1С-Битрикс и гарантируем качество. Получите консультацию — обсудим детали вашего магазина.
Технические детали (для разработчиков)
Стек: Vue.js 3, Pinia, TypeScript, Vite. Сборка — через Webpack или Vite, подключается как отдельный entry-point в шаблоне. Компонент не конфликтует с другими Vue-приложениями на странице.
Свойства инфоблока, участвующие в сравнении, помечаются флагом COMPARE = 'Y' — это стандартный механизм Битрикс, не требующий дополнительного кода.
Типичные ошибки и их решение
- Забыли про синхронизацию для авторизованных. Без неё список теряется при очистке кэша браузера.
- Не учли лимит на количество товаров. Больше 4–5 товаров в сравнении перегружают интерфейс — лучше ограничить.
- Сделали таблицу без фиксированной колонки на мобилках. Пользователь не видит названия характеристик при горизонтальном скролле.
Все эти проблемы мы решаем на этапе разработки — обратитесь к нам за консультацией.
Заключение
Сравнение товаров — важный инструмент для покупателей, которые выбирают среди похожих позиций. Правильно реализованное сравнение помогает принять решение на сайте, а не уйти на агрегатор. Наш компонент — это быстро, современно и адаптивно. Хотите улучшить UX своего магазина? Свяжитесь с нами — обсудим детали и подготовим коммерческое предложение.







