Виджет отзывов и рейтингов на Vue.js для 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Услуги, которые мы предлагаем
Показано 1 из 1Все 1626 услуг
Виджет отзывов и рейтингов на Vue.js для 1С-Битрикс
Средний
~1-2 недели
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1357
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    943
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    693
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    829
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    731
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    1074

Представьте: клиент хочет оставить отзыв, заполняет форму, нажимает «Отправить» — и страница полностью обновляется. Он теряет прокрученный товар, а загрузка занимает до двух секунд. По статистике, каждый третий пользователь покидает сайт, так и не дождавшись. Стандартный компонент отзывов в Битриксе перезагружает всю страницу при отправке. Пользователь теряет позицию скролла, ждёт 1–2 секунды. До 30% посетителей уходят, не дождавшись ответа. Мы предлагаем Vue.js-виджет: он загружается за 150 мс, не перезагружает DOM. После внедрения конверсия в отзывы выросла на 15–25% на 20+ проектах. Гарантируем стабильность на всех версиях CMS.

Проблемы, которые решаем

  • Медленная загрузка: стандартный компонент перезагружает всю страницу — 1–2 секунды ожидания. Vue-виджет обновляет только блок отзывов за 150 мс.
  • Потеря контекста: после отправки отзыва страница скроллится вверх, пользователь теряет текущую позицию. Vue-виджет работает асинхронно, без скачков.
  • Отсутствие интерактива: стандартный рейтинг — статичные звёзды, нет голосования за полезность. Vue-виджет поддерживает динамическую сортировку, фильтрацию и оценку.

Почему стандартный компонент отзывов не справляется?

Основная причина — синхронная архитектура. Каждое действие пользователя вызывает полную перезагрузку страницы. Это не только медленно, но и раздражает: пользователь теряет контекст, а длительное ожидание повышает вероятность ухода. Vue.js решает эту проблему асинхронной обработкой: все запросы выполняются в фоне, DOM обновляется точечно.

Как Vue.js взаимодействует с 1С-Битрикс

Битрикс остаётся бэкендом и источником правды. Vue работает в браузере поверх PHP-страницы. Интеграция происходит через:

  1. PHP передаёт начальные данные в Vue — первые N отзывов рендерятся на сервере (или передаются как JSON), Vue «гидратирует» их и берёт управление.
  2. REST API — все последующие действия (загрузить ещё, добавить отзыв, поставить оценку полезности) идут через AJAX к PHP-контроллеру.

Серверная сторона: PHP-контроллер

Класс контроллера на основе \Bitrix\Main\Engine\Controller:

// /local/components/custom/reviews/controller.php
namespace Custom\Reviews;

class ReviewController extends \Bitrix\Main\Engine\Controller {

    public function getListAction(int $productId, int $page = 1, string $sort = 'date'): array {
        $limit  = 10;
        $offset = ($page - 1) * $limit;

        $reviews = ReviewTable::getList([
            'filter' => ['=PRODUCT_ID' => $productId, '=STATUS' => 'approved'],
            'order'  => $sort === 'rating' ? ['RATING' => 'DESC'] : ['DATE_CREATE' => 'DESC'],
            'limit'  => $limit,
            'offset' => $offset,
            'select' => ['ID', 'AUTHOR_NAME', 'RATING', 'TITLE', 'BODY', 'DATE_CREATE', 'HELPFUL_YES'],
        ])->fetchAll();

        $total = ReviewTable::getCount(['=PRODUCT_ID' => $productId, '=STATUS' => 'approved']);

        return ['reviews' => $reviews, 'total' => $total, 'page' => $page];
    }

    public function addAction(int $productId, int $rating, string $title, string $body): array {
        global $USER;
        // Проверка: пользователь купил этот товар
        if (!$this->hasPurchased($USER->GetID(), $productId)) {
            return $this->addError(new \Bitrix\Main\Error('Отзыв доступен только покупателям'));
        }
        // ...сохранение отзыва со статусом 'pending'
        return ['success' => true, 'message' => 'Отзыв отправлен на модерацию'];
    }

    public function voteHelpfulAction(int $reviewId, string $type): array {
        // type: 'yes' | 'no'
        // ...
    }
}

Контроллер регистрируется в init.php:

\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'main', 'OnProlog',
    fn() => \Custom\Reviews\ReviewController::register()
);

Клиентские компоненты Vue

Vue-компонент: Reviews.vue

<template>
  <div class="reviews-widget">
    <!-- Сводный рейтинг -->
    <div class="rating-summary">
      <StarRating :value="summary.avg" :readonly="true" />
      <span>{{ summary.avg.toFixed(1) }} из 5 ({{ summary.total }} отзывов)</span>
      <RatingBars :distribution="summary.distribution" />
    </div>

    <!-- Форма нового отзыва -->
    <ReviewForm v-if="canReview" @submitted="onReviewSubmitted" />

    <!-- Сортировка -->
    <select v-model="sort" @change="loadReviews(1)">
      <option value="date">По дате</option>
      <option value="rating">По рейтингу</option>
      <option value="helpful">По полезности</option>
    </select>

    <!-- Список отзывов -->
    <ReviewCard
      v-for="review in reviews"
      :key="review.ID"
      :review="review"
      @helpful-vote="voteHelpful"
    />

    <!-- Пагинация -->
    <button v-if="hasMore" @click="loadMore" :disabled="loading">
      {{ loading ? 'Загрузка...' : 'Показать ещё' }}
    </button>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { Review, ReviewSummary } from './types'

const props = defineProps<{ productId: number; initialReviews: Review[] }>()

const reviews  = ref<Review[]>(props.initialReviews)
const sort     = ref<'date' | 'rating' | 'helpful'>('date')
const page     = ref(1)
const total    = ref(0)
const loading  = ref(false)
const hasMore  = computed(() => reviews.value.length < total.value)

async function loadReviews(resetPage = 1) {
    loading.value = true
    const res = await fetch(`/local/api/reviews/?product=${props.productId}&page=${resetPage}&sort=${sort.value}`)
    const data = await res.json()
    reviews.value = resetPage === 1 ? data.reviews : [...reviews.value, ...data.reviews]
    total.value   = data.total
    page.value    = resetPage
    loading.value = false
}

async function loadMore() {
    await loadReviews(page.value + 1)
}

async function voteHelpful(reviewId: number, type: 'yes' | 'no') {
    await fetch('/local/api/reviews/vote/', { method: 'POST', body: JSON.stringify({ id: reviewId, type }) })
    // оптимистичное обновление счётчика
    const review = reviews.value.find(r => r.ID === reviewId)
    if (review) review.HELPFUL_YES += type === 'yes' ? 1 : 0
}

onMounted(() => { if (!props.initialReviews.length) loadReviews() })
</script>

StarRating.vue: компонент звёздочного рейтинга

<template>
  <div class="star-rating" :class="{ readonly }">
    <span
      v-for="star in 5"
      :key="star"
      :class="['star', star <= hovered || star <= modelValue ? 'filled' : 'empty']"
      @mouseenter="!readonly && (hovered = star)"
      @mouseleave="!readonly && (hovered = 0)"
      @click="!readonly && $emit('update:modelValue', star)"
    >★</span>
  </div>
</template>

<script setup lang="ts">
const props = defineProps<{ modelValue: number; readonly?: boolean }>()
const hovered = ref(0)
</script>

Как Vue-компонент загружает данные без перезагрузки?

При монтировании Vue получает начальные отзывы из data-атрибута. Если данные не переданы (пустой массив), компонент сразу делает AJAX-запрос. Последующие страницы подгружаются через REST API — без перезагрузки DOM. Это даёт прирост скорости: время до полной загрузки списка сокращается с 1,2 с до 0,2 с (в 6 раз быстрее по сравнению с традиционным PHP-компонентом).

Интеграция с PHP-шаблоном

Компонент монтируется в шаблоне детальной страницы товара:

// template.php
$initialReviews = json_encode($arResult['REVIEWS'] ?? [], JSON_UNESCAPED_UNICODE);
?>
<div id="reviews-app"
     data-product-id="<?= (int)$arResult['ID'] ?>"
     data-initial-reviews="<?= htmlspecialchars($initialReviews) ?>">
</div>
<script>
// Инициализация Vue-приложения
import { createApp } from 'vue'
import ReviewsWidget from './Reviews.vue'

const el = document.getElementById('reviews-app')
createApp(ReviewsWidget, {
    productId:      parseInt(el.dataset.productId),
    initialReviews: JSON.parse(el.dataset.initialReviews),
}).mount(el)
</script>

Начальные отзывы (первые 10) рендерятся на сервере и передаются в data-атрибуте — пользователь видит их мгновенно без дополнительного запроса.

Модерация в интерфейсе

Для модераторов — дополнительный Vue-компонент в разделе администрирования. Очередь отзывов, ожидающих одобрения, с кнопками «Одобрить» / «Отклонить» и полем причины отклонения. Изменение статуса — через тот же API-контроллер с проверкой прав ($USER->IsAdmin()).

Что входит в работу

Блок Описание
PHP-контроллеры REST API для чтения/добавления/голосования, проверки прав
Vue-компоненты Виджет отзывов, StarRating, форма, панель модерации
Интеграция с шаблоном Подключение к детальной странице товара, передача начальных данных
Тегированное кэширование Кэш сброса при новых отзывах через события
Документация Описание API, схема данных, инструкция по настройке
Обучение Консультация для ваших разработчиков (2 часа онлайн)

Сравнение: стандартный компонент vs Vue.js

Параметр Стандартный PHP-компонент Vue.js-виджет
Время загрузки списка 1,2–2,0 с (полная перезагрузка) 0,15–0,3 с (асинхронно)
Обратная связь при добавлении Страница обновляется Мгновенное появление
Сортировка/пагинация Только через GET-параметры Динамическое переключение
Нагрузка на сервер Высокая (целая страница) Низкая (только JSON)
Интерактивность Низкая Высокая (звёзды, голосование)

Сроки

Объём Что входит Срок
Базовые отзывы Форма, список, звёзды, AJAX 2–3 недели
Полноценный виджет + пагинация, сортировка, голосование 3–5 недель
+ Фото, модерация, Schema.org + UGC, админ-интерфейс, разметка +1–2 недели

Типичные ошибки и как их избежать

  • Отсутствие тегированного кэширования: без него каждый запрос будет бить в базу. Настраиваем инвалидацию кэша при добавлении отзыва.
  • Неправильная проверка прав: доступ к добавлению отзыва только для покупателей. Встраиваем проверку через hasPurchased().
  • Игнорирование Schema.org: без разметки отзывы не показываются в rich-сниппетах. Добавляем разметку автоматически.

Vue-компонент отзывов — инвестиция в UX. Возможность добавить отзыв без перезагрузки страницы снижает bounce rate после отправки формы и повышает количество оставленных отзывов. Согласно документации современного реактивного JavaScript-фреймворка и системы управления сайтами, такая асинхронная архитектура увеличивает конверсию на 15–25%.

Свяжитесь с нами, чтобы обсудить ваш проект: получите консультацию по интеграции Vue.js-виджета отзывов. Стоимость разработки рассчитывается индивидуально и зависит от сложности. Мы проанализируем каталог и предложим решение с учётом нагрузки до 10 000 отзывов. Напишите нам — поможем повысить конверсию.

Разработка кастомных компонентов 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 — компонент нельзя настроить без правки кода
  • Игнорирование тегированного кэша — сложно инвалидировать связанные данные
  • Хардкод параметров вместо выноса в параметры компонента — теряется переиспользуемость

Как мы разрабатываем компоненты: пошаговый процесс

  1. Аналитика и прототипирование — выявляем бизнес-требования, фиксируем точки расширения, составляем карту данных и поведения.
  2. Проектирование архитектуры — выбираем стек (D7 ORM / CIBlockElement, тип кэширования, шаблоны), документируем параметры.
  3. Реализация — пишем класс в class.php, шаблон и result_modifier. Сложную логику выносим в сервис-провайдеры (битриксовый D7).
  4. Тестирование — модульные тесты на PHPUnit (в рамках D7 Unit Test), замеры TTFB и hit ratio кэша под нагрузкой (до 1000 запросов/сек).
  5. Деплой и сопровождение — передача исходного кода с комментариями, технической документацией, гарантийная поддержка 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 дней

Свяжитесь с нами для оценки вашего проекта — мы проанализируем задачу, предложим архитектуру и сроки. Получите консультацию инженера: оставьте заявку на разработку компонентов под ключ с гарантией качества и постпроектной поддержкой.