Динамические компоненты

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

Ключевая идея заключается в том, что компонент во Vue — это обычный JavaScript-объект, и его можно выбирать так же, как любое другое значение: по строке, по ссылке на объект или по вычисляемому выражению.


Тег <component> и атрибут is

Базовый механизм динамических компонентов реализован через встроенный тег <component>. Он служит контейнером, внутрь которого Vue подставляет конкретный компонент.

<component :is="currentComponent" />

Значение is определяет, какой компонент будет отрисован. Оно может быть:

  • строкой с именем зарегистрированного компонента
  • объектом компонента
  • результатом вычисляемого свойства

Пример с именами компонентов:

export default {
  data() {
    return {
      currentComponent: 'UserProfile'
    }
  }
}

Vue сопоставляет строку с локальной или глобальной регистрацией компонента и подставляет соответствующий шаблон.


Переключение компонентов по состоянию

На практике динамические компоненты почти всегда связаны с состоянием приложения.

<button @click="view = 'ListView'">Список</button>
<button @click="view = 'GridView'">Сетка</button>

<component :is="view" />
export default {
  data() {
    return {
      view: 'ListView'
    }
  }
}

Изменение значения view приводит к полной замене текущего компонента другим. При этом Vue корректно управляет жизненным циклом: старый компонент уничтожается, новый создаётся.


Использование объектов компонентов напрямую

Передача компонента как объекта избавляет от привязки к строковым именам.

import ListView from './ListView.vue'
import GridView from './GridView.vue'

export default {
  data() {
    return {
      current: ListView
    }
  }
}
<component :is="current" />

Такой подход повышает надёжность и упрощает рефакторинг, так как отсутствует зависимость от строк.


Сохранение состояния с <keep-alive>

По умолчанию при переключении динамических компонентов их состояние теряется. Для сохранения используется встроенный компонент <keep-alive>.

<keep-alive>
  <component :is="currentComponent" />
</keep-alive>

Особенности поведения:

  • компонент не уничтожается, а деактивируется
  • повторное отображение возвращает сохранённое состояние
  • жизненный цикл дополняется хуками activated и deactivated

Это критично для форм, вкладок и сложных интерфейсов, где повторная инициализация нежелательна.


Ограничение кешируемых компонентов

<keep-alive> поддерживает фильтрацию:

<keep-alive include="UserProfile,SettingsPanel">
  <component :is="currentComponent" />
</keep-alive>

Также доступны варианты:

  • exclude
  • регулярные выражения
  • массивы имён

Фильтрация работает только со строковыми именами компонентов.


Динамические компоненты и слоты

Динамические компоненты полностью поддерживают слоты.

<component :is="currentComponent">
  <template #header>
    Заголовок
  </template>
</component>

Слоты передаются в конкретный компонент и обрабатываются так же, как при статическом использовании. Это позволяет создавать универсальные контейнеры с подменяемой логикой и фиксированной структурой.


Передача пропсов и событий

Передача данных и событий работает стандартным образом.

<component
  :is="currentComponent"
  :user="user"
  @save="handleSave"
/>

Vue автоматически проксирует props и emits в активный компонент. Типизация и валидация пропсов сохраняются.


Асинхронные динамические компоненты

Компоненты можно загружать лениво, что особенно эффективно в сочетании с динамической подстановкой.

const AsyncProfile = () => import('./UserProfile.vue')

export default {
  data() {
    return {
      currentComponent: AsyncProfile
    }
  }
}

Преимущества:

  • уменьшение начального размера бандла
  • загрузка компонентов только при необходимости
  • естественная интеграция с динамическими интерфейсами

Обработка состояний загрузки и ошибок

Для асинхронных компонентов можно явно задать поведение.

const AsyncComp = defineAsyncComponent({
  loader: () => import('./Panel.vue'),
  loadingComponent: LoadingSpinner,
  errorComponent: LoadError,
  delay: 200,
  timeout: 3000
})

Такой компонент можно использовать внутри <component :is="..."> без дополнительных условий в шаблоне.


Динамические компоненты и маршрутизация

Несмотря на схожесть с <router-view>, динамические компоненты не заменяют маршрутизатор. Основные различия:

  • <router-view> управляется URL
  • динамические компоненты управляются локальным состоянием
  • маршруты поддерживают историю браузера и навигацию

На практике динамические компоненты часто используются внутри одного маршрута для управления внутренними состояниями страницы.


Типичные сценарии использования

Вкладки интерфейса Каждая вкладка — отдельный компонент, подставляемый динамически.

Мастера шагов Компоненты шагов подменяются в зависимости от текущего этапа.

Редакторы и панели Разные типы данных отображаются разными компонентами при общей обёртке.

CMS и админ-панели Тип контента определяет используемый компонент визуализации.


Ограничения и особенности

  • переключение без <keep-alive> приводит к потере состояния
  • анимации требуют <transition> вокруг <component>
  • фильтрация <keep-alive> работает только с именами
  • чрезмерная динамика усложняет отладку

Совмещение с <transition>

Для анимированного переключения используется стандартный механизм переходов.

<transition name="fade" mode="out-in">
  <component :is="currentComponent" />
</transition>

Режим out-in гарантирует корректную последовательность: сначала скрытие старого компонента, затем показ нового.


Архитектурные рекомендации

  • использовать динамические компоненты для логически взаимозаменяемых частей
  • избегать вложенной динамики без необходимости
  • комбинировать с keep-alive осознанно
  • отдавать предпочтение объектам компонентов вместо строк

Динамические компоненты являются фундаментальным инструментом Vue.js, позволяющим строить гибкие, масштабируемые и производительные пользовательские интерфейсы без усложнения шаблонов и логики управления состоянием.