Skip to content

Teleport组件

1. 基本概念

1.1 什么是Teleport

Teleport是Vue3提供的一个内置组件,允许我们将组件的一部分模板"传送"到当前组件DOM层次结构之外的DOM节点中。

1.2 主要用途

  • 模态框(Modal)实现
  • 弹出提示
  • 悬浮菜单
  • 全局通知

2. 基本用法

2.1 基础示例

vue
<template>
  <div class="container">
    <teleport to="body">
      <div class="modal">
        <!-- 模态框内容 -->
      </div>
    </teleport>
  </div>
</template>

2.2 动态控制

vue
<template>
  <button @click="showModal = true">打开模态框</button>
  
  <teleport to="body">
    <div v-if="showModal" class="modal">
      <h2>模态框标题</h2>
      <p>模态框内容</p>
      <button @click="showModal = false">关闭</button>
    </div>
  </teleport>
</template>

3. 高级特性

3.1 多个目标

vue
<template>
  <teleport to="#modal-container">
    <modal-content />
  </teleport>
  
  <teleport to="#notification-container">
    <notification-content />
  </teleport>
</template>

3.2 条件传送

vue
<template>
  <teleport to="body" :disabled="!shouldTeleport">
    <modal-content />
  </teleport>
</template>

<script>
export default {
  data() {
    return {
      shouldTeleport: true
    }
  }
}
</script>

4. 实际应用场景

4.1 模态框组件

vue
<!-- Modal.vue -->
<template>
  <teleport to="body">
    <div v-if="modelValue" class="modal-overlay">
      <div class="modal">
        <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('update:modelValue', false)">关闭</button>
          </slot>
        </div>
      </div>
    </div>
  </teleport>
</template>

4.2 通知系统

vue
<!-- Notification.vue -->
<template>
  <teleport to="#notification-container">
    <transition-group name="notification">
      <div
        v-for="notice in notices"
        :key="notice.id"
        class="notification"
      >
        {{ notice.message }}
      </div>
    </transition-group>
  </teleport>
</template>

5. 性能优化

5.1 按需传送

vue
<template>
  <teleport to="body" v-if="shouldRender">
    <heavy-component />
  </teleport>
</template>

5.2 动态目标

vue
<script>
export default {
  data() {
    return {
      teleportTarget: '#app'
    }
  },
  mounted() {
    // 根据条件动态改变传送目标
    this.teleportTarget = this.isMobile ? '#mobile-container' : '#desktop-container'
  }
}
</script>

6. 最佳实践

6.1 组件封装

vue
<!-- BaseModal.vue -->
<template>
  <teleport to="body">
    <transition name="modal">
      <div v-if="modelValue" class="modal-container">
        <div class="modal-content">
          <slot />
        </div>
      </div>
    </transition>
  </teleport>
</template>

<script>
export default {
  props: {
    modelValue: Boolean
  },
  emits: ['update:modelValue']
}
</script>

6.2 样式处理

vue
<style scoped>
.modal-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

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

7. 注意事项

  1. 目标元素必须存在
  2. SSR注意事项
  3. 样式作用域问题
  4. 事件冒泡处理
  5. 多个Teleport的协调

8. 与其他特性配合

8.1 与Transition结合

vue
<teleport to="body">
  <transition name="modal">
    <div v-if="show" class="modal">
      <!-- 模态框内容 -->
    </div>
  </transition>
</teleport>

8.2 与Vuex结合

js
// store.js
export const useModalStore = defineStore('modal', {
  state: () => ({
    activeModals: new Set()
  }),
  actions: {
    showModal(modalId) {
      this.activeModals.add(modalId)
    },
    hideModal(modalId) {
      this.activeModals.delete(modalId)
    }
  }
})