标准答案

  1. Teleport 解决的是渲染位置问题。组件逻辑仍然写在当前组件里,但 DOM 可以挂到 body 或指定容器下。
  2. 弹窗、抽屉、Popover、全局 Toast 常用 Teleport,因为这些 UI 不应该被父级 overflow、transform、z-index 或 stacking context 限制。
  3. Teleport 不会改变组件父子关系。props、emits、provide / inject、响应式状态仍然按原组件树工作。
  4. 使用 Teleport 时仍要处理焦点管理、滚动锁定、Esc 关闭、点击遮罩关闭和可访问性语义。
  5. 目标容器要稳定存在。SSR 或条件挂载场景下,要注意客户端和服务端渲染结果是否一致。

题目解析

Teleport 的重点不是让组件变成全局组件,而是让 DOM 离开原来的布局上下文。

弹窗如果留在深层组件里,容易被父容器 overflow hidden 裁剪,或者被局部 z-index 影响。

Teleport 只解决挂载位置,不负责弹窗交互完整性。可访问性和滚动控制仍然要自己或组件库处理。

代码示例

弹窗的触发状态留在当前组件里,弹窗 DOM 挂到 body 下。

Vue
<script setup lang="ts">
import { ref } from 'vue'

const visible = ref(false)
</script>

<template>
  <button type="button" @click="visible = true">
    打开弹窗
  </button>

  <Teleport to="body">
    <div v-if="visible" class="modal-mask">
      <section role="dialog" aria-modal="true">
        <h2>确认操作</h2>
        <button type="button" @click="visible = false">
          关闭
        </button>
      </section>
    </div>
  </Teleport>
</template>

常见误区

  • 认为 Teleport 会改变组件通信关系。它只改变 DOM 挂载位置。
  • 用了 Teleport 后忽略焦点恢复和键盘关闭,弹窗对键盘用户不可用。
  • 目标容器不存在,导致 Teleport 挂载失败或 SSR hydration 不一致。

作者信息