概述
Vue 3 引入了 Teleport 组件,它允许开发者将组件内容“传送”到 DOM 中的任意位置,不受常规组件渲染树的限制。
Teleport 是 Vue 3 的内置组件,用于将组件的模板内容渲染到页面的指定位置,即使这个位置在组件的挂载点之外。这在处理模态框、弹出框或全局头部等布局和嵌套问题时非常有用。
Teleport组件属性使用说明:
interface TeleportProps {
/**
* 必填项。指定目标容器。
* 可以是选择器或实际元素,
* 示例: <Teleport to="#some-id" />
<Teleport to=".some-class" />
<Teleport to="[data-teleport]" />
*/
to: string | HTMLElement
/**
* 当值为 `true` 时,内容将保留在其原始位置
* 而不是移动到目标容器中。
* 可以动态更改。
*/
disabled?: boolean
/**
* 当值为 `true` 时,Teleport 将推迟
* 直到应用的其他部分挂载后
* 再解析其目标。(3.5+)
*/
defer?: boolean
}
基本用法
点击按钮后,模态框会显示,并且通过 Teleport 被渲染到 body 下,而不是在按钮的旁边。
代码示例:
<template>
<div>
<!-- 正常渲染的按钮 -->
<button @click="showModal = true">打开模态框</button>
<!-- Teleport组件,将模态框内容渲染到body标签下 -->
<teleport to="body">
<div v-if="showModal" class="modal">
<!-- 模态框内容 -->
<p>这是一个模态框</p>
<button @click="showModal = false">关闭</button>
</div>
</teleport>
</div>
</template>
<script>
export default {
data() {
return {
showModal: false
};
}
};
</script>
<style>
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
border: 1px solid black;
}
</style>
Teleport 也可以用于创建弹出提示和下拉选项等组件,它们可以被渲染到页面的任何位置。
代码例子:
<template>
<div>
<button @click="showToast = true">显示提示</button>
<teleport to="body">
<div v-if="showToast" class="toast" @click="showToast = false">
<p>这是一个弹出提示</p>
</div>
</teleport>
</div>
</template>
<script>
export default {
data() {
return {
showToast: false
};
}
};
</script>
<style>
.toast {
position: fixed;
top: 20px;
right: 20px;
background: #333;
color: white;
padding: 10px 20px;
border-radius: 5px;
}
</style>
有条件地禁用
<Teleport to="#popup" :disabled="displayVideoInline">
<video src="./my-movie.mp4">
</Teleport>
延迟目标解析(3.5+版本支持)
<Teleport defer to="#late-div">...</Teleport>
<!-- 稍后出现于模板中的某处 -->
<div id="late-div"></div>
Teleport 使用的注意事项
- Teleport 会将组件的内容移动到 DOM 树之外的位置,但这些内容仍然是 Vue 组件的一部分,因此可以正常使用 Vue 的响应式数据和方法。
- 使用 Teleport 时,需要注意事件冒泡和样式隔离的问题,确保事件正确处理,并且样式不会相互干扰。
- Teleport 提供了 disabled 属性,当设置为 true 时,Teleport 将不会移动内容,而是在原位置渲染
** 日常实战使用遇到的场景提示:组件内插槽禁用Teleport
看以下例子:
<!-- 定义一个组件BaseLayout -->
<BaseLayout>
<template v-slot:header>
<!-- 一般 插槽的内容放这里 -->
<!--**
当你想使用Teleport包含这个内容,想把这个内容传到另外的节点去,
而不是放在BaseLayout组件内时,抱歉!这样不支持。
**-->
// 这里写Teleport,内容AA只能在原地,不会如你所愿传到节点#late-div下的
<Teleport defer to="#late-div">内容AA</Teleport>
</template>
</BaseLayout>