Skip to main content

Vue 3 Teleport:把 DOM 送到元件樹之外

<Teleport> 把一段範本渲染到目前元件 DOM 樹之外的指定位置,同時保留 Vue 元件樹中的狀態與邏輯階層。

<Teleport> 是 Vue 3 的內建元件(Built-in Component)。邏輯上它仍屬於某個子元件,視覺上卻可以把 DOM 掛到 <body> 或其他容器,避免被父層 CSS 裁切或壓在錯誤的層級。


一、解決的核心痛點

有些 UI 在邏輯上屬於深層子元件,在視覺與 DOM 結構上卻比較適合放在最外層(例如 <body> 底下):

  • 模態框(Modal / Dialog)
  • 全域通知(Toast / Notification)
  • 浮動選單(Tooltip / Dropdown)

若直接嵌在深層父元件的 DOM 內,容易被父層 CSS 干擾:

  1. overflow: hidden:彈窗內容被父容器裁切。
  2. z-index 層疊上下文(Stacking Context):父層有 transformfilter 或較低的 z-index 時,彈窗蓋不過頁面上其他元素。

<Teleport> 把實際 DOM 搬到目標節點,上述限制就不再綁在原本的父容器上。


二、基本語法與範例

to 指定目標 DOM 節點,可為 CSS 選擇器(如 body#modals)或實際的 DOM 物件。

<script setup>
import { ref } from 'vue'

const open = ref(false)
</script>

<template>
<button @click="open = true">開啟彈跳視窗</button>

<!-- 將內部內容傳送到 <body> 標籤的最下方 -->
<Teleport to="body">
<div v-if="open" class="modal-overlay">
<div class="modal-content">
<p>這是一個不受父層 CSS 限制的 Modal!</p>
<button @click="open = false">關閉</button>
</div>
</div>
</Teleport>
</template>

<style scoped>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
}
</style>

v-if 仍寫在 Teleport 內部即可:關閉時不會在 body 留下空節點。


三、重要特性

1. 邏輯與狀態依舊在原地

DOM 被搬到 <body>,Vue 元件樹的層級不變。內容仍可存取父元件的 propsref,也能 $emit 事件給父元件。

2. 動態禁用(disabled

:disabled="isMobile" 可動態決定是否傳送。為 true 時內容留在原本位置渲染,常用於響應式(例如手機版內嵌、桌面版彈窗)。

3. 多個 Teleport 聚集到同一目標

多個元件都傳送到同一個目標(如 to="#modals")時,內容會依掛載順序依序附加在該目標內。


四、總結

面向行為
DOM渲染到 to 指定的節點
元件樹邏輯、狀態、事件仍屬於原本父元件
典型用途Modal、Toast、Tooltip,避開 overflow 與 stacking context

官方文件:Teleport | Vue.js