前言
如果你写过中后台系统,一定遇到过这些场景:
-
❌ 模态框被 overflow: hidden裁剪
-
❌ 弹窗永远 z-index不够大
-
❌ 组件嵌套层级太深,样式被污染
-
❌ 全屏 loading 无法覆盖全局
在 Vue2 时代,我们通常这样解决:
-
手动 appendToBody
-
操作 DOM
-
提升 z-index
Vue3 给出的官方解决方案是:
✅ Teleport(传送门)
一、什么是 Teleport?
一句话定义:
Teleport 可以把组件渲染到 DOM 树的任意位置。
<Teleport to="body">
<Modal />
</Teleport>
📌 注意:
Teleport 不改变组件逻辑,只改变 DOM 挂载位置。
二、为什么需要 Teleport?
1️⃣ 没有 Teleport 的问题
App
├─ Layout
│ ├─ Content
│ │ ├─ Page
│ │ │ └─ Modal ❌
❌ Modal 被包裹在复杂 DOM 结构中
❌ 样式、定位、层级全部受限
2️⃣ 使用 Teleport 之后
App
├─ Layout
│ ├─ Content
│ │ └─ Page
│
└─ body
└─ Modal ✅
✅ 脱离父级 DOM 限制
三、Teleport 的基本用法
1️⃣ to属性(核心)
<Teleport to="body">
<div class="modal">我是弹窗</div>
</Teleport>
|
body |
渲染到 body |
|
#app |
渲染到 #app |
|
.class |
渲染到第一个匹配元素 |
2️⃣ 完整示例(模态框)
<script setup>
import { ref } from 'vue'
const visible = ref(false)
</script>
<template>
<button @click="visible = true">打开弹窗</button>
<Teleport to="body">
<div v-if="visible" class="modal">
<div class="content">
<p>这是一个全局弹窗</p>
<button @click="visible = false">关闭</button>
</div>
</div>
</Teleport>
</template>
四、Teleport 的关键特性
✅ 1️⃣ 组件逻辑不变
// Modal.vue
defineProps({
visible: Boolean
})
Teleport 不会影响:
-
Props
-
Emit
-
生命周期
-
响应式数据
✅ 2️⃣ 可以多次使用
<Teleport to="body">
<ModalA />
</Teleport>
<Teleport to="body">
<ModalB />
</Teleport>
✅ 3️⃣ 支持条件渲染
<Teleport to="body" v-if="visible">
📌 推荐做法:
Teleport + v-if 控制显示隐藏
五、Teleport 的常见应用场景
✅ 1️⃣ 模态框(Modal)
<Teleport to="body">
<Modal />
</Teleport>
✅ 防止被父容器裁剪
✅ 2️⃣ 全局提示 / Toast
<Teleport to="body">
<Toast />
</Teleport>
✅ 永远在最上层
✅ 3️⃣ 悬浮层 / Dropdown
<Teleport to="body">
<Dropdown />
</Teleport>
✅ 避免滚动遮挡
✅ 4️⃣ 全屏 Loading
<Teleport to="body">
<FullScreenLoading />
</Teleport>
六、Teleport 与 z-index 的关系
📌 重要认知:
Teleport 不能替代 z-index,但能减少 z-index 的复杂度。
推荐 CSS 写法:
.modal {
position: fixed;
inset: 0;
z-index: 1000;
}
七、Teleport 常见误区
❌ 误区 1:Teleport 是路由跳转
<Teleport to="/other-page"> ❌
📌 Teleport 只操作 DOM,不控制路由。
❌ 误区 2:Teleport 可以跨应用
<Teleport to="#other-app"> ❌
📌 只能在当前应用内生效。
八、Teleport + 组件封装最佳实践
<!– BaseModal.vue –>
<template>
<Teleport to="body">
<div v-if="modelValue" class="modal">
<slot></slot>
</div>
</Teleport>
</template>
<script setup>
defineProps({
modelValue: Boolean
})
defineEmits(['update:modelValue'])
</script>
✅ 这是企业级组件的标准写法。
九、面试高频问答
Q1:Teleport 改变了组件的什么?
只改变 DOM 挂载位置,不改变组件逻辑。
Q2:Teleport 和 v-if 谁先执行?
v-if 控制是否存在,Teleport 控制挂载位置。
Q3:Teleport 能解决所有层级问题吗?
不能,仍需合理使用 z-index。
十、总结(实战 & 架构版)
-
Teleport 是 Vue3 的 DOM 传送能力
-
最适合模态框、Toast、Dropdown
-
不破坏组件逻辑
-
大幅降低样式和层级复杂度
📢 下期预告
👉 第 15 篇:Fragments 与 Suspense —— 多根节点与异步组件加载

