[Easy] Новые возможности Vue3
1. Какие новые возможности появились в Vue 3?
Какие основные новые возможности появились в Vue 3?
Vue 3 представил множество важных обновлений:
Основные возможности
- Composition API
- Teleport
- Fragment (множественные корневые узлы)
- Suspense
- Множественные привязки
v-model - Улучшенная поддержка TypeScript
- Улучшения производительности (меньший размер бандла, более быстрый рендеринг)
2. Teleport
Что такое Teleport?
Teleport позволяет рендерить часть компонента в другом месте дерева DOM без изменения принадлежности компонента или структуры логики.
Типичные случаи использования
Modal, Tooltip, Notification, Popover, оверлейные слои.
<template>
<div>
<button @click="showModal = true">Открыть модальное окно</button>
<Teleport to="body">
<div v-if="showModal" class="modal">
<div class="modal-content">
<h2>Заголовок модального окна</h2>
<p>Содержимое модального окна</p>
<button @click="showModal = false">Закрыть</button>
</div>
</div>
</Teleport>
</div>
</template>
<script setup>
import { ref } from 'vue';
const showModal = ref(false);
</script>
Почему Teleport полезен
- Решает проблемы stacking context / z-index
- Избегает обрезки из-за overflow предка
- Сохраняет логику компонента рядом, рендеря в другом месте
3. Fragment (множественные корневые узлы)
Что такое Fragment в Vue 3?
Vue 3 позволяет шаблону компонента иметь множественные корневые узлы.
В отличие от React, Vue использует неявные fragments (дополнительный тег <Fragment> не нужен).
Vue 2 vs Vue 3
Vue 2: требуется единственный корень.
<template>
<div>
<h1>Заголовок</h1>
<p>Содержимое</p>
</div>
</template>
Vue 3: множественные корни допустимы.
<template>
<h1>Заголовок</h1>
<p>Содержимое</p>
</template>
Почему Fragment важен
- Меньше лишних элементов-обёрток
- Лучшая семантика HTML
- Менее глубокое дерево DOM
- Чище стили и селекторы
Наследование атрибутов в компонентах с множественными корнями
При использовании шаблонов с множественными корнями атрибуты родителя (class, id и т.д.) не применяются автоматически к конкретному корню.
Используйте $attrs вручную.
<!-- Родитель -->
<MyComponent class="custom-class" id="my-id" />
<!-- Дочерний -->
<template>
<div v-bind="$attrs">Первый корень</div>
<div>Второй корень</div>
</template>
Вы можете управлять поведением с помощью:
<script setup>
defineOptions({
inheritAttrs: false,
});
</script>
Fragment в Vue vs React Fragment
| Характеристика | Vue 3 Fragment | React Fragment |
|---|---|---|
| Синтаксис | Неявный (тег не нужен) | Явный (<> или <Fragment>) |
| Обработка ключей | Обычные правила vnode/key в списках | Key поддерживается на <Fragment key=...> |
| Проброс атрибутов | Используйте $attrs вручную при множественных корнях | Нет прямых атрибутов fragment |
4. Suspense
Что такое Suspense?
Suspense — встроенный компонент для состояний загру зки асинхронных зависимостей.
Он рендерит резервный UI, пока разрешается асинхронный компонент/setup.
Базовое использование
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Загрузка...</div>
</template>
</Suspense>
</template>
<script setup>
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
);
</script>
Типичные случаи использования
- Загрузка асинхронных компонентов
- Асинхронные требования данных в
setup() - Скелетонные UI на уровне маршрутов или секций
5. Множественные v-model
Множественные привязки
v-model
Vue 3 поддерживает множественные привязки v-model на одном компоненте.
Каждая привязка соответствует prop + событию update:propName.
Vue 2 vs Vue 3
Vue 2: один паттерн v-model на компонент.
<CustomInput v-model="value" />
Vue 3: множественные именованные привязки v-model.
<CustomForm
v-model:username="username"
v-model:email="email"
v-model:password="password"
/>
Пример реализации компонента
<!-- CustomForm.vue -->
<template>
<div>
<input
:value="username"
@input="$emit('update:username', $event.target.value)"
/>
<input
:value="email"
@input="$emit('update:email', $event.target.value)"
/>
<input
:value="password"
@input="$emit('update:password', $event.target.value)"
/>
</div>
</template>
<script setup>
defineProps(['username', 'email', 'password']);
defineEmits(['update:username', 'update:email', 'update:password']);
</script>
6. Частые вопросы на собеседованиях
Частые вопросы на собеседованиях
Вопрос 1: когда следует использовать Teleport?
Нажмите, чтобы увидеть ответ
Используйте Teleport, когда визуальный рендеринг должен выйти за пределы локальных ограничений DOM:
- Модальные диалоги для избежания проблем со stacking/overflow родителя
- Tooltip/popover, которые не должны обрезаться
- Глобальные уведомления, рендерящиеся в выделенном корневом контейнере
Не используйте Teleport для обычного содержимого в потоке.