логотип PurpleSchool
логотип PurpleSchool

Работа с динамическими компонентами и данными в Vue

Автор

Олег Марков

Введение

Опыт построения современных веб-интерфейсов часто требует гибкого управления отображаемыми компонентами в зависимости от пользовательских действий или полученных данных. В экосистеме Vue существует несколько эффективных инструментов, которые позволяют динамически менять компоненты и манипулировать связанными с ними данными.

В этой статье вы разберете, как использовать динамические компоненты (component), как связывать с ними данные, когда потребуется управлять их состоянием или реализовать переиспользуемые шаблоны. Также я покажу, как организовывать их жизненный цикл, прокидывать props, работать с передачей событий и использовать слоты в динамических связках.

Что такое динамические компоненты в Vue

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

Общий подход

В основе работы с динамическими компонентами лежит специальный элемент <component>, которому через атрибут :is передается либо строковое имя компонента, либо сам объект компонента.

Пример:

<template>
  <!-- В зависимости от currentView, здесь отображается один из компонентов -->
  <component :is="currentView"></component>
</template>

<script>
import MyList from './MyList.vue'
import MyGrid from './MyGrid.vue'

export default {
  data() {
    return {
      // Выбор компонента может происходить динамически
      currentView: 'MyList'
    }
  },
  components: {
    MyList,
    MyGrid
  }
}
</script>

В этом примере, если currentView содержит 'MyList', будет отрисован компонент MyList. Если значение поменять на 'MyGrid', на этой же позиции появится MyGrid. Такой код идеально подходит для построения динамических секций интерфейса.

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

Использование props

Динамический компонент, как и обычный, может принимать props. Важно помнить: если у вас есть разные компоненты с разными набором props, стоит удостовериться, что передаваемые props есть у всех компонентов, иначе может быть предупреждение, либо не все props попадут туда, куда ожидали.

Вот пример — передаем данные в динамический компонент:

<template>
  <!-- Передаем user как prop каждому динамическому компоненту -->
  <component :is="selectedComponent" :user="userData"></component>
</template>

<script>
import UserCard from './UserCard.vue'
import UserProfile from './UserProfile.vue'

export default {
  data() {
    return {
      selectedComponent: 'UserCard',
      userData: { name: 'Anna', email: 'anna@mail.com' }
    }
  },
  components: {
    UserCard,
    UserProfile
  }
}
</script>

В этом случае оба компонента UserCard и UserProfile должны принимать проп user. Если нужен более гибкий способ — можно использовать v-bind="{...}" для передачи всех свойств сразу.

Передача всех props через v-bind

Если вы хотите передать сразу несколько props, можно использовать v-bind с объектом. Это удобно для унифицированных структур данных:

<component :is="active" v-bind="componentProps"></component>

<!-- компонентProps = { title: 'hello', subtitle: 'subtitle text', active: true } -->

Этот способ быстро раскрывает весь объект в props динамического компонента.

Смена компонента по событию

Вы часто встретите сценарии, когда требуется поменять активный компонент по клику или другому событию пользователя. Для этого достаточно просто обновить значение переменной, передаваемой в :is:

<template>
  <button @click="toggleView">Поменять вид</button>
  <component :is="current"></component>
</template>

<script>
import ViewA from './ViewA.vue'
import ViewB from './ViewB.vue'

export default {
  data() {
    return {
      current: 'ViewA'
    }
  },
  components: { ViewA, ViewB },
  methods: {
    toggleView() {
      // Меняет отображаемый компонент
      this.current = this.current === 'ViewA' ? 'ViewB' : 'ViewA'
    }
  }
}
</script>

Сразу при клике отрендерится другой компонент — быстро, без перерисовки всей страницы.

Уникальность состояния и key

Если у вас используются динамические компоненты, и при переключении нужно сохранять их состояние (например, введенные значения в форме), Vue позволяет это сделать через компонент <keep-alive>. Но если нужно сбрасывать внутреннее состояние компонентов при каждом переключении, стоит использовать уникальный key:

<component :is="currentView" :key="currentView"></component>

Здесь каждый раз при смене значения currentView компонент будет пересоздаваться заново и внутреннее состояние сбросится.

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

<keep-alive> сохраняет внутреннее состояние динамического компонента — это полезно для форм и тяжелых компонентов. Работает это очень просто:

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

Допустим, если вы вводите текст в форме в одном компоненте, переключаетесь, а затем возвращаетесь — все введенные данные останутся.

Настройки keep-alive

Вы можете ограничить какие именно компоненты держать в alive через include/exclude, используя строку с именами компонентов:

<keep-alive include="MyList,MyGrid">
  <component :is="currentView"></component>
</keep-alive>

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

Иногда требуется прокинуть индивидуальный контент в разный компонент. В Vue 3 доступны динамические слоты (Dynamic Slots) через объект:

<component 
  :is="dynamic" 
  v-bind="componentProps" 
  v-slot="slotProps">
  {{ slotProps.someData }}
</component>

Если хочется более контролируемо управлять содержимым для разных компонентов, рекомендую явно задавать имена слотов:

<component :is="tabComp">
  <template #header>
    <!-- будет использован слот header в любом из активных компонентов -->
    <h1>Заголовок для текущего компонента</h1>
  </template>
</component>

Динамические компоненты как шаблонные конструкторы

Если у вас есть однотипные шаблоны с разной логикой (например, Alert Success, Alert Error, Alert Info), используйте массив к компоненту:

<component 
  v-for="type in alertTypes" 
  :key="type" 
  :is="type" 
  :message="alertText[type]">
</component>

Здесь для каждого типа алерта будет свой компонент, и каждому из них можно прокинуть индивидуальные props.

Передача событий между динамическими компонентами

Вся работа с событиями (@event) абсолютно идентична работе с обычным компонентом. Например:

<component :is="widget" @save="handleSave"></component>

Здесь если внутренний компонент вызовет $emit('save'), этот обработчик сработает.

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

В Vue можно использовать динамические компоненты, которые еще не загружены — удобно для ленивой подгрузки:

<template>
  <component :is="asyncComponent"></component>
</template>

<script>
export default {
  data() {
    return {
      asyncComponent: () => import('./BigComponent.vue')
    }
  }
}
</script>

Теперь компонент подгрузится только тогда, когда будет показан во вьюхе, это ускоряет старт загрузки страницы.

Управление списками динамических компонентов

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

<template>
  <component
    v-for="item in widgets"
    :key="item.id"
    :is="item.type"
    v-bind="item.props">
  </component>
</template>

<script>
import WidgetA from './WidgetA.vue'
import WidgetB from './WidgetB.vue'

export default {
  data() {
    return {
      widgets: [
        { id: 1, type: 'WidgetA', props: { value: 10 }},
        { id: 2, type: 'WidgetB', props: { color: 'red' }}
      ]
    }
  },
  components: { WidgetA, WidgetB }
}
</script>

Динамическое подключение через ключ type подставляет компонент по его имени. Все необходимые props прокинутся через v-bind.

Типичные проблемы и нюансы

  • Значение атрибута :is обязательно должно быть строкой (именем зарегистрированного компонента) или объектом — иначе будет ошибка.
  • Все компоненты, которые вы хотите использовать динамически, должны быть заранее импортированы и зарегистрированы.
  • Если для разных компонентов нужны разные props, стоит использовать подход с общим родительским компонентом-оберткой.

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

Важный нюанс — если вы меняете props у динамического компонента, данные обновятся моментально, как и у обычных компонентов. Никаких специальных “магий” по синхронизации делать не требуется.

Однако если вы работаете с массивом динамических компонентов, обязательно следите за корректной установкой key во v-for, чтобы избежать "перемешивания" состояний между компонентами.

Работа с render-функциями для особо гибких случаев

В редких случаях, если недостаточно возможностей шаблонов, используйте render-функции или JSX (только при наличии соответствующего билда). Такой подход позволяет динамично подставлять компоненты по условиям и программно формировать вложенность.

Пример на обычной render-функции:

render(h) {
  // Программно выбираем компонент
  return h(this.current, {
    props: this.componentProps
  })
}

В большинстве случаев хватает декларативных шаблонов — программные рендеры нужны редко, например при написании библиотек.

Интеграция с Vue Router

С помощью <router-view> реализуются layout-подобные связи, где содержимое меняется динамически по маршруту. По сути, <router-view> — тоже динамический компонент.

Вы даже можете обернуть <router-view> в <keep-alive>, чтобы сохранять состояние вложенных страниц.

Заключение

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

Этот подход пригодится практически в любом “живом” проекте: от простых вкладок до сложных интерфейсов редактирования, работающих с большим количеством уникальных или повторяющихся блоков.


Частозадаваемые технические вопросы по теме статьи и ответы на них

Как прокинуть уникальные props разным динамическим компонентам?

Если у разных компонентов props с разными именами, используйте computed-поле, которое строит объект props по имени компонента:

computed: {
  currentProps() {
    if (this.currentView === 'CompA') return { foo: 1 }
    if (this.currentView === 'CompB') return { bar: 2 }
    return {}
  }
}

И вызывайте: <component :is="currentView" v-bind="currentProps"></component>

Как корректно динамически загружать компоненты на серверном рендеринге (SSR)?

Используйте async import с дефолтным экспортом:

const AsyncComp = () => import('./AsyncComp.vue')

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

Почему не обновляются props в динамическом компоненте при смене данных?

Проверьте, используется ли корректный key:

<component :is="comp" :key="compKey" :prop="val" />

Если key статичен, компонент не пересоздается и не всегда видит новые props.

Как слушать собственные события от вложенных динамических компонентов?

Всё как обычно: <component :is="current" @event="handler"></component>. Не забудьте, что вложенный компонент должен явно вызывать $emit('event').

Можно ли динамически выбирать компонент только на этапе рендера и не хранить его в data?

Да, просто использовать выражение:

<component :is="someCondition ? 'CompA' : 'CompB'"></component>

Это сокращает количество переменных в data, но подойдет не для всех кейсов, где быстрая смена нужна по клику.

Стрелочка влевоКомпоненты Vue создание передача данных события и emit3 способа манипулирования DOM на VueСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами и node modules в Vue проектахУправление пакетами Vue js с помощью npmКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний