首页 > 编程笔记 > JavaScript笔记 阅读:6

Vue Teleport组件的用法(附带实例)

Teleport 中文翻译为“瞬间移动”,顾名思义,Teleport 内置组件可以将组件中的一部分元素移动到指定的目标元素上。

Vue 项目中的所有组件都被包含在 App 这一根组件下,而在入口文件 main.js 中引入根组件 App 后会将其挂载于“#app”网页元素上,这就意味着 Vue 项目中的所有组件元素都被包含在“#app”网页元素中。

假如现在有一个需求,在网页的顶层显示一个模态框。如果可以实现模态框元素直接包含在 body 标签中,让该元素和“#app”网页元素同级并列,那么控制结果会变得简单,此时就可以使用具有移动功能的内置组件 Teleport 来实现。

下面就来实现这个需求,在 App 组件中引入一个具有弹出框的子组件 GlobalAlert,App.vue 文件代码如下:
<template>
  <GlobalAlert />
</template>

<script setup>
import GlobalAlert from './components/GlobalAlert.vue';
</script>

<style>
#app {
  text-align: center;
  background: #2c3e50;
  padding-top: 60px;
  height: 100vh;
}
</style>
子组件 GlobalAlert 上需要有两个功能按钮和一个模态框。按钮用于切换功能,需要显示在页面上,因此会被包含在“#app”网页元素中。而带有动画效果的模态框则与“#app”同级并列,这样更容易控制其出现在页面的顶层。可以通过在瞬间移动组件 Teleport 中将 to 属性值设置为“body”来实现效果。

此时 components/GlobalAlert.vue 文件代码如下:
<script setup>
import { ref } from 'vue';
const isOpen = ref(false);  // 控制是否显示模态框
const isTeleport = ref(false);  // 控制是否禁用 Teleport 组件
</script>

<template>
<!-- 按钮部分将被嵌套于“#app”网页元素中 -->
<button @click="isOpen = !isOpen">
  {{ isOpen ? '关闭' : '打开' }}模态框
</button>
<button @click="isTeleport = !isTeleport">
  {{ isTeleport ? '禁用' : '非禁用' }}移动功能
</button>
<!-- 利用Teleport 内置组件将其包含的元素移动到 body 标签内 -->
<Teleport to="body" :disabled="isTeleport">
<!-- 动画效果增强视觉 -->
<Transition mode="in-out">
<!-- 利用 v-if 指令控制模态框的显示与隐藏 -->
<div v-if="isOpen" class="modal">
  <p>元素被移动到 body 标签内,与 “#app” 网页元素是并列关系</p>
  <!-- 按钮点击事件控制模态框的隐藏与显示 -->
  <button class="close" type="button" @click="isOpen = false">
    关闭
  </button>
</div>
</Teleport>
</transition>
</template>

<style scoped>
.modal {
  position: fixed;
  isolation: isolate;
  z-index: 1;
  top: 2rem;
  left: 2rem;
  width: 20rem;
  border: 1px solid grey;
  padding: 0.5rem;
  border-radius: 1rem;
  background-color: grey;
  box-shadow: 2px 2px 4px grey;
  backdrop-filter: blur(4px);
  color: #f4f4f4;
}
button {
  padding: 0.5rem;
  border: 0;
  border-radius: 1rem;
  box-shadow: inset 0 -1px 4px grey, 1px 1px 2px grey;
  cursor: pointer;
  transition: box-shadow 0.15s ease-in-out;
}
button:hover {
  box-shadow: inset 0 -1px 2px grey, 1px 1px 2px grey;
}
.close {
  display: block;
  margin-left: auto;
}
/* 在没有设置 name 时可以设置统一的动画样式类名,以 v-xxx 方式命名 */
.v-enter-active,
.v-leave-active {
  transition: all 0.25s ease-in-out;
}
.v-enter-from,
.v-leave-to {
  opacity: 0;
  transform: translateX(-10vw);
}
</style>
运行代码,页面效果如下图所示:


图 1 页面效果

点击“打开模态框”按钮,会发现在页面顶层显示了一个模态框。利用 Vue 开发者调试工具中的 Elements 审查元素,可以确认“#app”网页元素和模态框元素是并列关系,模态框的 div 处于页面顶层 body 下,如下图所示:


图 2 “#app”网页元素和模态框元素并列

从图 1 中可以观察到,还有一个“非禁用移动功能”按钮,同样从代码中可以看到 disabled 属性的相关实现。disabled 属性可以确认是否禁用移动功能,如果 disabled 属性值为 true,则移动功能被禁用,反之可以使用。在禁用状态下,Teleport 组件内的元素仍旧保持不移动状态的元素位置。

点击“非禁用移动功能”按钮后,观察控制台可以发现模态框的 div 被包含在“#app”网页元素下,如下图所示:


图 3 模态框的div被包含在“#app”网页元素下

相关文章