Vue3内置组件Teleport/Suspense

发布于:2025-09-12 ⋅ 阅读:(21) ⋅ 点赞:(0)

Teleport

组件的渲染默认遵循 “父子嵌套” 规则,即子组件会渲染到父组件模板对应的 DOM 位置。但在实际开发中,有些组件(如弹窗、通知、加载提示)虽然在逻辑上属于某个父组件,却需要在视觉或功能上 “脱离” 父组件的 DOM 层级(比如固定在页面顶部、居中显示,或避免被父组件的样式(如 overflow: hidden)、z-index 限制)。

Teleport(译为 “瞬移”)就是为解决这类问题而生的内置组件,它能将组件的渲染内容 “传送” 到 DOM 树中的指定位置,实现 “逻辑归属不变、渲染位置灵活” 的效果。

使用场景:

这类场景最常见的例子就是全屏的模态框。

理想情况下,我们希望触发模态框的按钮和模态框本身的代码是在同一个单文件组件中,因为它们都与组件的开关状态有关。但这意味着该模态框将与按钮一起渲染在应用 DOM 结构里很深的地方,可能对于该模态框的布局代码会有些难写。

注意事项:

能想到的可能是position:fixed;以浏览器窗口为参照,进行全屏显示遮罩层,内部再写一个弹框,内部可以通过flex完成对弹窗的水平垂直居中。

这样的方案是有前提条件的,前提是该遮罩层不能有任何祖先元素设置了transformperspective 或者 filter 样式属性。否则会影响遮罩层的布局位置!

即使遮罩层已经fixed

接下来看如果遮罩层所属的祖先元素有设置transform会出现什么效果:遮罩层直接像右发生了偏移!这对于遮罩层的显示效果必然是有影响的,且影响用户的视觉效果。

而Vue3提供的内置组件 Teleport 就可以解决该问题,使用方法:

<!-- 让下面的div在显示时以body标签的子元素呈现 -->
<Teleport to="body">
  <div
    v-if="modelValue"
    class="modal-overlay"
  >
    <div class="modal-container">
        <p>弹框内容</p>
    </div>
  </div>
</Teleport>

属性to的值可以是CSS选择器,也可以是DOM元素对象

  • 例如:类选择器 .main 等
  • 例如:标签选择器 body 等
  • 例如:id选择器 #app 等

所以可以给自定义组件Modal外套上Teleport,指定body;下方效果正常,不再受偏移影响。

<Teleport to="body">
    <Modal
      v-model="showModal"
      title="确认一下!"
      size="default"
      :close-on-overlay-click="true"
      @close="handleModalClose"
      @confirm="handleModalConfirm"
    >
      <div>
        <p>订单详情:</p>
        <ul>
          <li>商品名称:xx</li>
          <li>单价:2</li>
          <li>数量:3</li>
          <li>总价:6</li>
        </ul>
      </div>
    </Modal>
</Teleport>

Suspense

核心作用是:在等待异步内容(异步组件、带异步数据的组件)加载完成时,先显示 “加载中” 的 fallback 内容,加载完成后再切换到目标内容。

本质是解决 “异步加载时的过渡体验” 问题。

使用场景:

组件依赖异步数据「当组件需要先请求数据(如接口获取列表、详情)才能渲染时」;

在代码中的常见体现:

  • 对setup采用了async处理;
export default {
  async setup() {
    const res = await fetch(...)
    const posts = await res.json()
    return {
      posts
    }
  }
}
  • 或者 在setup内部顶层使用了await;「顶层即最外层作用域」
<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>

<template>
  {{ posts }}
</template>

警告信息都说的这么明白了,还不上Suspense还得等什么?

使用方法:

 <Suspense> 组件有两个插槽:#default 和 #fallback。两个插槽都只允许一个直接子节点。在可能的时候都将显示默认插槽中的节点。否则将显示后备插槽中的节点。

<Suspense>
  <!-- 具有异步依赖的组件 -->
  <Dashboard />

  <!-- 备用组件  在 #fallback 插槽中显示 “正在加载中” -->
  <template #fallback>
    Loading...
  </template>
</Suspense>

使用实例:

当前页面中有列表组件,列表组件在数据准备好前可以先显示 骨架屏,以优化用户等待体验;在数据准备好后展示 数据列表结构。


网站公告

今日签到

点亮在社区的每一天
去签到