Реактивный компонент сравнения товаров на 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 своего магазина? Свяжитесь с нами — обсудим детали и подготовим коммерческое предложение.
Разработка кастомных компонентов 1С-Битрикс
Как result_modifier.php закрывает боли, которые не решает ядро
Берём типовой кейс: каталог на 50 000 товаров с торговыми предложениями. Штатный bitrix:catalog.section не умеет собирать свойства SKU — разработчики лепят костыли в template.php. Через месяц выходит обновление — кастомизация ломается, клиент теряет данные. Мы на практике выяснили: result_modifier.php решает это без правки ядра. Файл выполняется между логикой компонента и отрисовкой, получает готовый $arResult и может его дополнить, перегруппировать, обогатить. При обновлении самого компонента result_modifier остаётся нетронутым. Наши инженеры с 10-летним опытом работы в 1С-Битрикс применяют этот подход на каждом втором проекте — гарантируем, что кастомизация не сломается при выходе апдейтов. Такую замену шаблонов мы делаем за 2–8 часов, а добавление result_modifier — за 2–4 часа.
Типичные задачи, которые мы закрываем через result_modifier:
- Дотягиваем свойства торговых предложений через
CIBlockElement::GetList — складываем в $arResult['OFFERS_PROPS']
- Группировка элементов по разделам или произвольным свойствам (штатный отдаёт плоский массив, а дизайн требует табы)
- Расчёт скидок, рейтингов, сроков доставки — бизнес-логика, которой в стандартном компоненте нет
- Подготовка JSON-массивов для JavaScript:
$arResult['JS_DATA'] = json_encode(...) прямо в modifier, в шаблоне только <script>var data = <?=$arResult['JS_DATA']?></script>
Главное правило: тяжёлые запросы к БД в result_modifier допустимы, потому что он работает внутри зоны кэширования. А вот в component_epilog.php — нет, и это принципиально.
Почему component_epilog.php работает вне кэша и как это использовать
Выполняется после отрисовки шаблона и вне зоны кэширования — каждый хит, даже закэшированный. Сюда кладём:
- Проверку авторизации и персонализированные элементы: «Добавить в избранное», «Купить в 1 клик»
- Установку мета-тегов и заголовков через
$APPLICATION->SetTitle()
- Подключение JS/CSS через
Asset::getInstance()->addJs()
- Навигационную цепочку
Критично: никаких тяжёлых SQL здесь. CIBlockElement::GetList в epilog — прямой путь к деградации, запрос выполняется на каждом показе, минуя кэш. Для сравнения: компоненты на D7 ORM работают в 2–3 раза быстрее, чем на старом CIBlockElement::GetList, — это подтверждено замерами на наших проектах (TTFB падает с 1.2 с до 0.4 с).
Архитектура компонента: что входит в работу
| Файл |
Назначение |
| class.php |
ООП-класс, наследующий CBitrixComponent. Бизнес-логика, выборка данных, валидация параметров. В новых компонентах используем только его, component.php — процедурный пережиток. |
| template.php |
Чистый HTML + $arResult. Никакой бизнес-логики. |
| result_modifier.php |
Дополнительная обработка после выборки, но перед отрисовкой. |
| component_epilog.php |
Персонализация, мета-теги, скрипты — выполняется вне кэша. |
| .parameters.php |
Описание входных параметров для админки. |
| .description.php |
Метаданные: название, категория, иконка. |
Всё на ядре D7, ORM-классах и событийной модели. CIBlockElement::GetList — только когда D7 ORM не покрывает кейс. Документация по компонентам — на dev.1c-bitrix.ru. Общее понятие компонентной архитектуры — на Wikipedia.
Зачем кастомные компоненты, если есть готовые в маркетплейсе
Стандартных хватает для 80% сценариев. Но на каждом втором проекте появляется нетривиальная бизнес-логика, которую не закрыть настройками:
- Калькуляторы стоимости с многопараметрическими формулами
- Интеграционные компоненты для внешних API (CRM, ERP, логистика, CDEK, Битрикс24 REST)
- Мультишаговые конфигураторы товаров и системы бронирования
- Дашборды для административной панели
Принцип: компонент переиспользуемый — параметризация вместо хардкода. Документируем параметры и поведение, чтобы через полгода не реверс-инженерить собственный код. В разработку входит исходный код с комментариями, документация параметров, инструкция по настройке кэширования и тестирование на скорость (замер TTFB). Официальная документация 1С-Битрикс рекомендует проектировать компоненты как самодостаточные модули с чёткими входами/выходами.
Ajax: контроллеры D7
Встроенный ajax-режим каталожных компонентов (AJAX_MODE = Y) закрывает базу — пагинация, фильтры, сортировка без полной перезагрузки.
Для кастомной логики — контроллеры Bitrix\Main\Engine\Controller. Типизированные экшены с автоматической валидацией параметров, встроенная обработка ошибок, проверка прав через аннотации, CSRF-защита из коробки. Endpoint через ajax.php или кастомный роутинг. Ответ в JSON. Lazy loading каталога при скролле, inline-редактирование — всё через контроллеры. Подробнее о D7 контроллерах — на официальном портале.
Как кэширование определяет скорость сайта и экономит бюджет
Разница между 200 мс и 3 секунды — это стратегия кэширования. Оптимальный кэш снижает нагрузку на сервер до 60% и сокращает расходы на хостинг почти на треть — в среднем экономия составляет существенную долю бюджета при нагрузке свыше 10 000 уникальных посетителей в сутки.
- Управляемый кэш — автоинвалидация при изменении данных. Добавили товар в инфоблок — кэш пересоздался. Самый надёжный вариант для контентных компонентов. Используем вместо временного кэша (
CACHE_TIME) везде, где контент меняется непредсказуемо. Для сравнения: управляемый кэш эффективнее временного в 70% сценариев.
- Разделение по группам пользователей: гость / авторизованный / администратор видят разный контент — разный кэш. Персональные данные — строго в
component_epilog, вне кэша.
- Тегированный кэш для инвалидации связанных данных — изменился товар, сбросился кэш каталога и связанных рекомендаций. Это особенно важно при интеграции с 1С и Bizproc.
- Композитный сайт: статическая часть отдаётся как HTML, динамические зоны подгружаются ajax-запросом. TTFB < 100 мс. Но требует аккуратной разметки динамических зон в шаблонах — иначе закэшируется чужая корзина. Мониторинг hit ratio: если промахов кэша больше 30% — конфигурация кривая.
Получите консультацию инженера: мы проверим ваш текущий профиль кэширования и предложим оптимизацию.
Какие ошибки допускают при разработке кастомных компонентов
- Запросы к БД в component_epilog.php — убивают кэш
- Тяжёлая бизнес-логика в template.php — смешение представления и логики
- Отсутствие .parameters.php — компонент нельзя настроить без правки кода
- Игнорирование тегированного кэша — сложно инвалидировать связанные данные
- Хардкод параметров вместо выноса в параметры компонента — теряется переиспользуемость
Как мы разрабатываем компоненты: пошаговый процесс
-
Аналитика и прототипирование — выявляем бизнес-требования, фиксируем точки расширения, составляем карту данных и поведения.
-
Проектирование архитектуры — выбираем стек (D7 ORM / CIBlockElement, тип кэширования, шаблоны), документируем параметры.
-
Реализация — пишем класс в class.php, шаблон и result_modifier. Сложную логику выносим в сервис-провайдеры (битриксовый D7).
-
Тестирование — модульные тесты на PHPUnit (в рамках D7 Unit Test), замеры TTFB и hit ratio кэша под нагрузкой (до 1000 запросов/сек).
-
Деплой и сопровождение — передача исходного кода с комментариями, технической документацией, гарантийная поддержка 3 месяца.
Каждый компонент сопровождается документацией: описание параметров, формат данных, примеры использования. Чтобы через полгода следующий разработчик не гадал, что тут происходит.
Что входит в разработку компонента (deliverables)
- Полный стек файлов: class.php, template.php, result_modifier.php (при необходимости), .parameters.php, .description.php
- Инструкция по настройке кэширования и интеграции
- Описание параметров и формата данных (Markdown или doc)
- Исходный код с комментариями на русском
- Тестирование на скорость и корректность под нагрузкой
- Консультация по внедрению и гарантия поддержки 3 месяца
Оставьте заявку — мы проанализируем задачу, предложим архитектуру компонентов и сроки. Закажите разработку компонентов под ключ: получите готовое решение с постпроектной поддержкой.
Сроки разработки
| Тип задачи |
Сроки |
| Кастомный шаблон стандартного компонента |
2–8 часов |
| result_modifier с дополнительной логикой |
2–4 часа |
| Простой кастомный компонент |
1–3 дня |
| Сложный компонент с ajax и кэшированием |
3–7 дней |
| Интеграционный компонент (внешний API) |
3–10 дней |
Свяжитесь с нами для оценки вашего проекта — мы проанализируем задачу, предложим архитектуру и сроки. Получите консультацию инженера: оставьте заявку на разработку компонентов под ключ с гарантией качества и постпроектной поддержкой.