Teleport
<Teleport> 是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。
1.组件属性
<Teleport> 组件可接收以下属性
ts
interface TeleportProps {
/**
* 必填项。指定目标容器。
* 可以是选择器或实际元素。
*/
to: string | HTMLElement
/**
* 当值为 `true` 时,内容将保留在其原始位置
* 而不是移动到目标容器中。
* 可以动态更改。
*/
disabled?: boolean
/**
* 当值为 `true` 时,Teleport 将推迟
* 直到应用的其他部分挂载后
* 再解析其目标。(3.5+)
*/
defer?: boolean
}2.基本使用
<Teleport>一个比较好的创建就是我们自己封装Modal弹窗,若在一个组件中使用弹窗,其dom结构一定是跟着组件来的,但是使用<Teleport>我们可以把弹窗组件挂载到body身上
vue
<template>
<teleport to="body" v-if="show">
<div class="cover" @click="show = false">
<div class="modal">
<slot></slot>
</div>
</div>
</teleport>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
const showModal = () => {
show.value = true
}
</script>
<style lang="scss">
.cover {
position: fixed;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.2);
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
.modal {
width: 800px;
height: 500px;
border-radius: 5px;
background: #fff;
padding: 20px;
box-sizing: border-box;
}
}
</style>3.搭配组件使用
<Teleport> 只改变了渲染的 DOM 结构,它不会影响组件间的逻辑关系。
也就是说,如果 <Teleport> 包含了一个组件,那么该组件始终和这个使用了 <Teleport> 的组件保持逻辑上的父子关系。传入的 props 和触发的事件也会照常工作。
这也意味着来自父组件的注入也会按预期工作,子组件将在 Vue Devtools 中嵌套在父级组件下面,而不是放在实际内容移动到的地方。
4.指定目标容器
to属性可以传入一个HTMLElement,或者一个选择器字符串
vue
<Teleport to="#some-id" />
<Teleport to=".some-class" />
<Teleport to="[data-teleport]" />5.有条件地禁用
disabled属性可以禁止Teleport将里面的元素穿梭
vue
<Teleport to="#popup" :disabled="displayVideoInline">
<video src="./my-movie.mp4">
</Teleport>6.延迟目标解析
在 Vue 3.5 及更高版本中,我们可以使用 defer 属性推迟 Teleport 的目标解析,直到应用的其他部分挂载。这允许 Teleport 将由 Vue 渲染且位于组件树之后部分的容器元素作为目标:
vue
<Teleport defer to="#late-div">...</Teleport>
<!-- 稍后出现于模板中的某处 -->
<div id="late-div"></div>7.多个Teleport共享目标
一个可重用的模态框组件可能同时存在多个实例。对于此类场景,多个 <Teleport> 组件可以将其内容挂载在同一个目标元素上,而顺序就是简单的顺次追加,后挂载的将排在目标元素下更后面的位置上。
比如下面这样的用例:
html
<Teleport to="#modals">
<div>A</div>
</Teleport>
<Teleport to="#modals">
<div>B</div>
</Teleport>渲染的结果为:
html
<div id="modals">
<div>A</div>
<div>B</div>
</div>