开启掘金成长之旅!这是我参与「掘金日新计划 · 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或者触发的事件都不会受到破坏。