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

↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Переключение компонентов по данным: табы, визарды, рендер по схеме.

Объяснение

<script setup lang="ts">
import { shallowRef, markRaw, defineAsyncComponent } from "vue";
import TextField from "./TextField.vue"; import SelectField from "./SelectField.vue";
 
const map = { text: TextField, select: SelectField } as const;
const current = shallowRef<Component>(TextField);        // shallowRef/markRaw: компонент не должен быть глубоко реактивным
const fields = [{ type: "text", name: "a" }, { type: "select", name: "b" }];
</script>
 
<template>
  <component :is="current" v-bind="props" @change="onChange" />
 
  <!-- Рендер формы по схеме -->
  <component v-for="f in fields" :key="f.name" :is="map[f.type]" v-bind="f" v-model="model[f.name]" />
 
  <!-- Сохранение состояния переключаемых компонентов -->
  <KeepAlive :include="['Tab1']" :max="5"><component :is="tabs[active]" /></KeepAlive>
  <component :is="isLink ? 'a' : 'button'" :href="url" />          <!-- нативные теги -->
</template>

:is принимает: строку (имя зарегистрированного компонента или тега), сам компонент (объект/функцию).

Особенности:

  • Значение компонента храните в shallowRef (или markRaw), иначе Vue создаёт реактивный прокси над определением компонента (предупреждение и лишние расходы).
  • Переключение уничтожает предыдущий компонент; для сохранения состояния — <KeepAlive> (activated/deactivated).
  • Атрибуты и слушатели прокидываются на текущий компонент.
  • Для асинхронных вариантов — defineAsyncComponent (см. Асинхронные компоненты и lazy loading).

Использования: табы, динамические формы (schema-driven UI), рендер виджетов дашборда, полиморфные компоненты (as-prop).

Нюансы и подводные камни

  • Строка в :is в SFC требует регистрации компонента (глобально или resolveComponent).
  • Без KeepAlive состояние формы теряется при переключении.
  • Разные компоненты получают одни и те же props — лишние попадают в $attrs и DOM.
  • Обращение к слотам динамического компонента — как обычно.

Практика

  1. Сделайте табы с component :is и KeepAlive.
  2. Отрендерите форму по JSON-схеме полей.
  3. Реализуйте полиморфный Btn (a/button/RouterLink).

Вопросы с ответами

Связанные темы