Teleport 传送门 文章目录前言一、基本用法1.1 为什么需要 Teleport1.2 Teleport 解决二、to 属性2.1 指定目标位置2.2 挂载点准备2.3 disabled 动态控制三、典型场景3.1 Modal 对话框3.2 Toast 全局通知3.3 全屏 Loading3.4 Dropdown 下拉菜单四、逻辑归属与事件冒泡4.1 组件树 vs DOM 树4.2 事件冒泡遵循组件树4.3 多个 Teleport 到同一目标五、SSR 行为5.1 默认原位渲染5.2 处理方案六、面试聚焦6.1 事件冒泡遵循组件树6.2 Teleport 在 SSR 时的行为6.3 Teleport 解决了什么问题七、易混淆点八、思考与练习总结前言Teleport是 Vue 3 内置组件可将子元素的 DOM 传送到页面其他位置突破父容器的 CSS 限制。本篇会讲清楚Teleport 的基本用法与to属性Modal、Toast、Loading 等典型场景逻辑归属与事件冒泡规则SSR 下的行为一、基本用法1.1 为什么需要 Teleport!-- 问题Modal 嵌套在组件内可能被父容器裁切 -- div classpage styleoverflow: hidden; position: relative; button clickopen true打开弹窗/button div v-ifopen classmodal !-- z-index 可能失效 -- 弹窗内容 /div /div父容器的overflow: hidden、transform、z-index等会限制子元素显示。Modal 需要渲染到body下才能全屏覆盖。1.2 Teleport 解决template button clickopen true打开弹窗/button Teleport tobody div v-ifopen classmodal-mask div classmodal-content p弹窗内容/p button clickopen false关闭/button /div /div /Teleport /template script setup import { ref } from vue const open ref(false) /script style .modal-mask { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 9999; } /styleDOM 渲染到body末尾但组件的 props、emit、生命周期仍属于父组件。二、to 属性2.1 指定目标位置!-- 传送到 body -- Teleport tobody.../Teleport !-- 传送到指定 id -- Teleport to#modal-root.../Teleport !-- 传送到 class -- Teleport to.app-container.../Teleportto接受 CSS 选择器字符串目标元素必须已存在于 DOM 中。2.2 挂载点准备!-- index.html --bodydividapp/divdividmodal-root/div!-- 可选专用挂载点 --/bodyTeleport to#modal-root Modal v-ifvisible / /Teleport2.3 disabled 动态控制Teleport tobody :disabledisMobile Modal / /Teleportdisabled为true时内容渲染在 Teleport 原位不传送SSR 或移动端回退时常用。三、典型场景3.1 Modal 对话框!-- components/Modal.vue -- template Teleport tobody Transition namefade div v-ifmodelValue classmodal-mask click.selfclose div classmodal-box slot / button clickclose关闭/button /div /div /Transition /Teleport /template script setup defineProps({ modelValue: Boolean }) const emit defineEmits([update:modelValue]) const close () emit(update:modelValue, false) /script配合Transition实现淡入淡出Teleport 确保遮罩覆盖全屏。3.2 Toast 全局通知!-- components/Toast.vue -- template Teleport tobody div classtoast-container TransitionGroup nametoast div v-formsg in messages :keymsg.id classtoast-item {{ msg.text }} /div /TransitionGroup /div /Teleport /template style .toast-container { position: fixed; top: 20px; right: 20px; z-index: 10000; } /styleToast 固定在视口右上角不受页面滚动和父容器影响。3.3 全屏 Loadingtemplate Teleport tobody div v-ifloading classloading-mask div classspinner加载中.../div /div /Teleport /template style .loading-mask { position: fixed; inset: 0; background: rgba(255, 255, 255, 0.8); display: flex; align-items: center; justify-content: center; z-index: 99999; } /style3.4 Dropdown 下拉菜单template div classdropdown-trigger clickopen !open 选择项 /div Teleport tobody div v-ifopen classdropdown-menu :style{ top: menuTop px, left: menuLeft px } div v-foritem in options :keyitem{{ item }}/div /div /Teleport /template下拉菜单传送到 body避免被overflow: auto的表格或侧边栏裁切。四、逻辑归属与事件冒泡4.1 组件树 vs DOM 树Vue 组件树App → Page → Modal逻辑父子 DOM 树 body → div#app → ... ; body → div.modalTeleport 渲染位置Teleport只改变 DOM 位置不改变 Vue 组件树props / emit 仍走父组件生命周期仍属于定义 Teleport 的组件父组件可通过v-if控制 Teleport 内容4.2 事件冒泡遵循组件树!-- Parent.vue -- template div clickhandleParentClick Child / /div /template !-- Child.vue -- template Teleport tobody button clickhandleClick按钮/button /Teleport /template点击 Teleport 内的按钮click在 Child 组件内触发 → 沿Vue 组件树向 Parent 冒泡不会冒泡到 DOM 中 Teleport 的实际父元素如 body4.3 多个 Teleport 到同一目标Teleport to#modal-root ModalA v-ifshowA / /Teleport Teleport to#modal-root ModalB v-ifshowB / /Teleport多个 Teleport 传送到同一容器时按声明顺序追加到目标内。五、SSR 行为5.1 默认原位渲染服务端渲染时Teleport默认不传送内容渲染在组件原位 DOM 中。客户端 hydration 完成后才传送到to目标可能造成短暂闪烁。5.2 处理方案!-- 方案一SSR 时禁用 Teleport -- Teleport tobody :disabled!isClient Modal / /Teleport script setup import { ref, onMounted } from vue const isClient ref(false) onMounted(() { isClient.value true }) /script// 方案二Nuxt 等框架内置 SSR Teleport 支持// 需在服务端提供 #teleports 挂载点生产环境使用 Nuxt 等 SSR 框架时按框架文档配置 Teleport 挂载点。六、面试聚焦6.1 事件冒泡遵循组件树Teleport 只移动 DOM不改变 Vue 组件树。事件仍按组件父子关系冒泡不会冒泡到 DOM 中的实际父元素。6.2 Teleport 在 SSR 时的行为默认在原位渲染不传送。客户端激活后才移动到目标位置。可通过disabled或框架配置处理。6.3 Teleport 解决了什么问题Modal、Toast 等需要全屏/固定定位的 UI避免被父容器overflow、z-index、transform裁切或遮挡。七、易混淆点只改 DOM 不改组件树props/emit/生命周期仍属原组件。事件不沿 DOM 冒泡沿 Vue 组件树冒泡。to 目标必须存在挂载前 DOM 中需有对应元素。SSR 默认不传送hydration 后才移动注意闪烁问题。与 Portal 类似React Portal 概念相同Vue 3 内置为 Teleport。八、思考与练习1.Teleport 的作用是什么解析将子元素 DOM 传送到页面其他位置如 body突破父容器 CSS 限制逻辑仍属原组件。2.Modal 为什么常用 Teleport 到 body解析避免被父容器 overflow、z-index、transform 裁切确保遮罩全屏覆盖。3.Teleport 内点击事件如何冒泡解析遵循 Vue 组件树冒泡不遵循 DOM 树。事件向定义 Teleport 的组件的父级传递。4.SSR 时 Teleport 的行为解析默认在原位渲染客户端 hydration 后才传送到 to 目标。5.disabled 属性有什么用解析为 true 时不传送内容渲染在原位。SSR 回退或条件禁用传送时使用。总结TeleportVue 3 内置将 DOM 传送到指定位置逻辑仍属原组件toCSS 选择器指定目标body、#id、.class典型场景Modal、Toast、Loading、Dropdown事件冒泡遵循组件树不遵循 DOM 树SSR默认原位渲染需注意 hydration 闪烁