技术文档中心
首页
React
Vue
TypeScript
Kotlin
React Native
Electron
Android
首页
React
Vue
TypeScript
Kotlin
React Native
Electron
Android
  • Vue2 基础

    • Vue 学习指南
    • Vue2 快速入门
    • Vue2 模板语法
    • Vue2 组件基础
    • Vue2 计算属性与侦听器
    • Vue2 生命周期
  • Vue2 进阶

    • Vue2 组件通信
    • Vue2 插槽详解
    • Vue2 混入与自定义指令
    • Vue2 过渡与动画
    • Vuex 状态管理
  • Vue2 高级

    • Vue2 性能优化
    • Vue2 服务端渲染(SSR)
    • Vue2 源码解析
  • Vue3 基础

    • Vue3 快速入门
    • Vue3 Composition API
    • Vue3 响应式系统
    • Vue3 组件基础
    • Vue3 生命周期
  • Vue3 进阶

    • Vue3 组合式函数
    • Vue3 组件通信
    • Vue3 Teleport 与 Suspense
    • Pinia 状态管理
    • Vue Router 4
  • Vue3 高级

    • Vue3 TypeScript
    • Vue3 性能优化
    • Vue3 测试
    • Vue3 SSR
    • Vue3 源码解析
  • 实战项目

    • Vue2 实战项目
    • Vue3 实战项目
    • Vue2 迁移 Vue3

Vue3 Teleport 与 Suspense

Teleport

Teleport 允许我们将组件的 HTML 渲染到 DOM 中的任意位置。

基本用法

<template>
  <button @click="open = true">打开模态框</button>

  <Teleport to="body">
    <div v-if="open" class="modal">
      <p>这是一个模态框</p>
      <button @click="open = false">关闭</button>
    </div>
  </Teleport>
</template>

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

const open = ref(false)
</script>

禁用 Teleport

<Teleport :disabled="isMobile" to="body">
  <div>内容</div>
</Teleport>

多个 Teleport

<Teleport to="#modals">
  <div>Modal 1</div>
</Teleport>

<Teleport to="#modals">
  <div>Modal 2</div>
</Teleport>

实际应用:模态框组件

<!-- Modal.vue -->
<template>
  <Teleport to="body">
    <Transition name="modal">
      <div v-if="show" class="modal-mask" @click="$emit('close')">
        <div class="modal-container" @click.stop>
          <div class="modal-header">
            <slot name="header">默认标题</slot>
          </div>
          <div class="modal-body">
            <slot></slot>
          </div>
          <div class="modal-footer">
            <slot name="footer">
              <button @click="$emit('close')">关闭</button>
            </slot>
          </div>
        </div>
      </div>
    </Transition>
  </Teleport>
</template>

<script setup>
defineProps({
  show: Boolean
})
defineEmits(['close'])
</script>

<style scoped>
.modal-mask {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-container {
  background: white;
  border-radius: 8px;
  padding: 20px;
  max-width: 500px;
}
</style>

Suspense

Suspense 用于协调异步依赖的处理。

基本用法

<template>
  <Suspense>
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback>
      <div>加载中...</div>
    </template>
  </Suspense>
</template>

<script setup>
import AsyncComponent from './AsyncComponent.vue'
</script>

异步组件

<!-- AsyncComponent.vue -->
<script setup>
const data = await fetch('/api/data').then(r => r.json())
</script>

<template>
  <div>{{ data }}</div>
</template>

异步 setup

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

const data = ref(null)

// 顶层 await
data.value = await fetch('/api/data').then(r => r.json())
</script>

错误处理

<template>
  <Suspense @pending="onPending" @resolve="onResolve" @fallback="onFallback">
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback>
      <div>加载中...</div>
    </template>
  </Suspense>
</template>

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

const onPending = () => console.log('pending')
const onResolve = () => console.log('resolved')
const onFallback = () => console.log('fallback')

onErrorCaptured((err) => {
  console.error('Error:', err)
  return false
})
</script>

嵌套 Suspense

<template>
  <Suspense>
    <template #default>
      <ParentComponent>
        <Suspense>
          <template #default>
            <ChildComponent />
          </template>
          <template #fallback>
            <div>子组件加载中...</div>
          </template>
        </Suspense>
      </ParentComponent>
    </template>
    <template #fallback>
      <div>父组件加载中...</div>
    </template>
  </Suspense>
</template>

实际应用

<template>
  <Suspense>
    <template #default>
      <UserProfile :id="userId" />
    </template>
    <template #fallback>
      <div class="loading">
        <Spinner />
        <p>加载用户信息...</p>
      </div>
    </template>
  </Suspense>
</template>

<script setup>
import { ref } from 'vue'
import UserProfile from './UserProfile.vue'
import Spinner from './Spinner.vue'

const userId = ref(1)
</script>
最近更新: 2026/1/27 15:51
Contributors: hailong
Prev
Vue3 组件通信
Next
Pinia 状态管理