Vue 3 實戰:掌握 Teleport 傳送門,完美解決 Modal 彈窗與 CSS 層級限制
在開發複雜的前端介面時,我們經常會遇到 邏輯在內層,樣式在外層 的矛盾。最典型的範例就是 Modal(彈窗) 或 Tooltip(提示框)。
Vue 3 提供的 Teleport 元件,能讓您將元件的 HTML 結構 傳送 到 DOM 階層以外的指定位置(例如 <body> 標籤直屬下方),同時還能完整保留該元件內部的資料狀態與邏輯。
使用 Teleport 的理由
如果在一個深度嵌套的元件裡寫了一個全螢幕彈窗(Modal),會遇到以下麻煩:
- CSS 限制:如果外層元件設定了
overflow: hidden或z-index,彈窗可能會被遮擋或切掉。 - DOM 層級混亂:為了讓彈窗蓋住全螢幕,可能被迫把彈窗元件寫在
App.vue最外層,這會導致邏輯分散,按鈕在內層元件,彈窗卻在外層元件。
核心價值
Teleport 讓您實現了 邏輯封裝與視圖分離:您可以在內層元件編寫彈窗程式碼(方便管理邏輯),但最終渲染出來的 DOM 卻出現在 <body> 或您指定的任何地方。
基本用法:指定您的傳送目標
<teleport> 接收一個 to 屬性,用來指定目標容器。這個值可以是任何 CSS 選取器,如 to="body"、to="#app-modals" 或是實際的 DOM 元素。
實戰範例:封裝一個不受限的 Modal
父元件呼叫方式
vue
<!-- /views/Slot.vue -->
<script setup>
import Modal from "@/components/Modal.vue";
</script>
<template>
<Modal />
</template>Modal 元件內部實作
vue
<!-- /components/Modal.vue -->
<script setup>
import { ref } from "vue";
const open = ref(false);
</script>
<template>
<button @click="open = true">Open Modal</button>
<teleport to="body">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</teleport>
</template>
<style scoped>
.modal {
position: fixed;
z-index: 999;
top: 20%;
left: 50%;
width: 300px;
margin-left: -150px;
}
</style>Teleport 的關鍵特性
- 保留狀態:雖然 DOM 位置變了,但內部的
ref、reactive以及從父層接收的props依然維持響應式連動。 - 多個傳送門:多個
<teleport>可以同時指向同一個目標元素,如同一個to="body",Vue 會按照順序將它們依序掛載。 - Disabled 模式:您可以透過
:disabled="true"屬性暫時停用傳送功能,讓內容回到原本的位置。
總結
Teleport 是 Vue 3 中處理彈窗、通知與下拉選單的標準解答。它完美解決了 CSS 層級競爭問題,同時確保了元件開發的封裝性,讓您的 UI 架構更加穩健且易於調試。
