Vue中的Teleport

75 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

前言

当我们有一个组件,我们不想让它局限在当前父组件的DOM结构中,而是想让传送到指定的DOM结构下时,你可能会很头疼,但是,现在你可以不用头疼了,vue提供了一个<Teleport>的内置组件,它可以很好的帮你解决这个问题,更加游刃有余的控制组件在DOM中的渲染位置。

<Teleport>

你可能会想什么样的场景下我们需要把组件的DOM结构渲染在指定的位置,而不是按照组件的逻辑嵌套关系来渲染。

很显然,一个全屏的模态框就是很好的例子。

正常情况下,我们会把触发模态框的按钮以及模态框本身放在一个组件中,因为它们本身都与组件的开关状态相关联。相应的,编写模态框的央视你可能会遇到一些问题。

我们先来看一下模态框的实现方法:

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

const open = ref(false)
</script>

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

  <div v-if="open" class="Modal">
    <p>这里假装是一个弹窗!</p>
    <button @click="open = false">关闭</button>
  </div>
</template>

<style scoped>
.Modal {
  width: 300px;
  position: fixed;
  top: 20%;
  left: 50%;
  margin-left: -150px;
  z-index: 99;
}
</style>

可以看到,这个组件通过一个button打开模态框,并通过名为Modal的class进行样式更改,以及modal内部的button进行关闭。

尽管这样可以实现我们的功能,但一些潜在的问题也无法让人忽视:

  • position: fixed虽然很好的解决了模态框的定位,但如果它的祖先元素设置transform、perspective以及filter 不为 none 的样式时,就会破坏模态框的布局,当然这也是fixed本身的问题。

  • z-index也受限于它的容器元素,因为一旦有其他元素的z-index值更高,就会破坏模态框的样式。

<Teleport>的出现可以让我们很好的规避这些问题。

<button @click="open = true">打开</button>

<Teleport to="body">
  <div v-if="open" class="Modal">
    <p>这里假装是一个弹窗!</p>
    <button @click="open = false">关闭</button>
  </div>
</Teleport>

通过 <Teleport> 的to prop 可以指定传送的地点,其接收的值是一个CSS选择器字符串或者DOM元素对象。

这样当我们把他传送到body标签下面时,就不会受到影响了。

并且也不会打破其与组件之间的逻辑关系,传递的prop或者触发的事件都不会受到破坏。