Skip to main content
Практика завдань

Телепортація у Vue.js

Що таке Teleport?

Teleport — це вбудований компонент Vue 3, який дозволяє рендерити контент в будь-якому місці DOM, навіть поза кореневим елементом Vue додатку.

Це особливо корисно для модальних вікон, підказок, сповіщень та інших елементів, які повинні бути поза поточною ієрархією.


Основне використання

javascript
<template> <div class="component"> <button @click="showModal = true">Відкрити модальне вікно</button> <Teleport to="body"> <div v-if="showModal" class="modal"> <p>Я рендерюся в body!</p> <button @click="showModal = false">Закрити</button> </div> </Teleport> </div> </template> <script setup> import { ref } from 'vue' const showModal = ref(false) </script> <style scoped> .modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; z-index: 1000; } </style>

Контент <Teleport> буде рендеритися в <body>, а не всередині .component.


Селектори для to

Атрибут to приймає CSS селектор або DOM елемент:

CSS Селектор

javascript
<!-- За ID --> <Teleport to="#modal-container"> <div>Контент</div> </Teleport> <!-- За класом --> <Teleport to=".modal-wrapper"> <div>Контент</div> </Teleport> <!-- За тегом --> <Teleport to="body"> <div>Контент</div> </Teleport>

DOM Елемент

javascript
<script setup> import { ref, onMounted } from 'vue' const targetElement = ref(null) onMounted(() => { targetElement.value = document.getElementById('custom-container') }) </script> <template> <Teleport :to="targetElement" v-if="targetElement"> <div>Контент</div> </Teleport> </template>

Вимкнення Teleport

Ви можете динамічно вмикати/вимикати телепортацію:

javascript
<template> <Teleport to="body" :disabled="!isMobile"> <div class="modal"> На мобільному - в body, на десктопі - тут </div> </Teleport> </template> <script setup> import { ref, onMounted } from 'vue' const isMobile = ref(false) onMounted(() => { isMobile.value = window.innerWidth < 768 }) </script>

Кілька Teleport до однієї цілі

Ви можете телепортувати кілька компонентів в одне місце:

javascript
<!-- Component1.vue --> <Teleport to="#notifications"> <div>Сповіщення 1</div> </Teleport> <!-- Component2.vue --> <Teleport to="#notifications"> <div>Сповіщення 2</div> </Teleport>
html
<!-- index.html --> <div id="app"></div> <div id="notifications"></div>

Обидва сповіщення будуть рендеритися в #notifications у порядку монтування.


Практичні приклади

Модальне вікно

javascript
<!-- Modal.vue --> <template> <Teleport to="body"> <Transition name="modal"> <div v-if="isOpen" class="modal-overlay" @click="close"> <div class="modal-content" @click.stop> <button class="modal-close" @click="close">×</button> <slot /> </div> </div> </Transition> </Teleport> </template> <script setup> defineProps({ isOpen: Boolean }) const emit = defineEmits(['close']) function close() { emit('close') } </script> <style scoped> .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 1000; } .modal-content { background: white; padding: 20px; border-radius: 8px; max-width: 500px; position: relative; } .modal-close { position: absolute; top: 10px; right: 10px; background: none; border: none; font-size: 24px; cursor: pointer; } </style>

Використання:

javascript
<template> <button @click="isModalOpen = true">Відкрити</button> <Modal :is-open="isModalOpen" @close="isModalOpen = false"> <h2>Заголовок</h2> <p>Контент модального вікна</p> </Modal> </template> <script setup> import { ref } from 'vue' import Modal from './Modal.vue' const isModalOpen = ref(false) </script>

Teleport vs CSS position: fixed

Без Teleport

javascript
<template> <div class="parent" style="position: relative; overflow: hidden"> <div class="modal" style="position: fixed"> <!-- Може бути обрізане через overflow: hidden --> </div> </div> </template>

Проблеми:

  • Може бути обрізане батьківським overflow
  • Спадковує контекст z-index
  • Важко керувати порядком накладання

З Teleport

javascript
<template> <div class="parent" style="position: relative; overflow: hidden"> <Teleport to="body"> <div class="modal" style="position: fixed"> <!-- Завжди відображається правильно --> </div> </Teleport> </div> </template>

Переваги:

  • Незалежний від стилів батька
  • Власний контекст накладання
  • Легко керувати z-index

Обмеження

Цільовий елемент повинен існувати

javascript
<!-- Неправильно --> <Teleport to="#non-existent"> <div>Помилка!</div> </Teleport> <!-- Правильно --> <Teleport to="body"> <div>Працює!</div> </Teleport>

Teleport не змінює логічну ієрархію

javascript
<script setup> import { provide } from 'vue' provide('theme', 'dark') </script> <template> <Teleport to="body"> <!-- inject все ще працює! --> <ChildComponent /> </Teleport> </template>

Пропси, події, provide/inject продовжують працювати, оскільки змінюється лише DOM, а не ієрархія компонентів.


Висновок

Teleport:

  • Рендерить контент в будь-якому місці DOM
  • Не змінює логічну ієрархію компонентів
  • Корисний для модальних вікон, підказок, сповіщень
  • Вирішує проблеми з переповненням та z-index
  • Може бути динамічно вимкнений
  • Підтримує кілька телепортацій до однієї цілі

На співбесідах:

Важливо вміти:

  • Пояснити, що таке Teleport і чому він потрібен
  • Показати приклади використання (модальні вікна, сповіщення)
  • Описати проблеми, які вирішує Teleport
  • Пояснити, що логічна ієрархія не змінюється
  • Навести відмінності від CSS position: fixed

Контент

Що таке Teleport?Основне використанняСелектори для toCSS СелекторDOM ЕлементВимкнення TeleportКілька Teleport до однієї ціліПрактичні прикладиМодальне вікноTeleport vs CSS position: fixedБез TeleportЗ TeleportОбмеженняЦільовий елемент повинен існуватиTeleport не змінює логічну ієрархіюВисновок

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань