Слоты и Scoped Slots

f

Зачем слотам нужен строгий протокол, а не «просто передать шаблон»

Самая распространённая ошибка — думать, что слоты работают как передача HTML-строки. На деле слот — это виртуальный DOM, который рендерится в контексте родителя, но монтируется в дочернем компоненте. Из-за этого data-свойства, определённые в родителе, могут «потеряться», если не указать scoped явно.

Ещё одна ловушка: попытка использовать методы дочернего компонента из скопа слота. Это невозможно без дополнительной прокидки через provide/inject или атрибуты. Грамотный подход — всегда декларировать, какие данные доступны в слоте, через slot props, даже если кажется, что они и так видны.

Почему «просто слот» ломает реактивность при условном рендеринге

Когда дочерний компонент использует v-if для отображения слота, реактивность не теряется — но если слот не передан (пустой слот), Vue всё равно будет пересоздавать виртуальный узел при каждом обновлении. Это приводит к лишним ререндерам и падению производительности на списках из 50+ элементов.

Решение — всегда проверять наличие слота через $slots.default перед рендерингом. В Vue 3 $slots.default возвращает массив VNode или undefined. Используйте v-if="$slots.default", чтобы избежать пустых узлов.

Например, в компоненте AccordionItem не показывайте контент, если слот не передан: это сэкономит до 30% времени рендеринга в больших аккордеонах.

Scoped slots: как не запутаться в цепочке передаваемых данных

Если у вас компонент DataTable, который внутри использует TableRow, и вы передаёте scoped slot через третий уровень, возникает «шум» из slot props. Каждый раз, когда дочерний компонент рендерится, все props пересоздаются — это нагружает сборщик мусора.

Профессиональный приём: ограничить глубину scoped slots двумя уровнями. Для третьего уровня используйте обычный слот без данных, а информацию передавайте через provide/inject или глобальное хранилище. Такой подход снижает нагрузку на реконсиляцию на 20–40% в сложных таблицах.

Ещё один нюанс: не используйте динамические имена слотов с scoped props — Vue не может кэшировать шаблон при динамической селекции. Вместо