1. 作用与场景(参考 vue3-Teleport)
一个组件模板的一部分在逻辑上从属于该组件,但从整个应用视图的角度来看,它在 DOM 中应该被渲染在整个 Vue 应用外部的其他地方。这类场景最常见的例子就是全屏的模态框。
<Teleport>
只改变了渲染的 DOM 结构,它不会影响组件间的逻辑关系。也就是说,如果<Teleport>
包含了一个组件,那么该组件始终和这个使用了<Teleport>
的组件保持逻辑上的父子关系。传入的 props 和触发的事件也会照常工作。
这也意味着来自父组件的注入也会按预期工作,子组件将在 Vue Devtools 中嵌套在父级组件下面,而不是放在实际内容移动到的地方。
2. 用法
模态框组件
<template>
<div class="dialog">
<div class="info">确定删除吗?</div>
<div class="btn">
<button @click="confirm" class="confirm">确定</button>
<button class="cancel">取消</button>
</div>
</div>
</template>
<script setup lang="ts">
const emit = defineEmits(['on-confirm'])
const confirm = () => {
emit('on-confirm')
}
</script>
<style scoped>
.dialog {
width: 300px;
height: 300px;
border: 1px solid #fff;
border-radius: 5px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: rgb(255, 241, 47);
}
.info {
color: red;
text-align: center;
font-size: 20px;
height: 200px;
line-height: 200px;
}
.btn {
display: flex;
}
.btn button {
display: block;
margin: auto;
width: 80px;
height: 30px;
border: 1px solid #ccc;
cursor: pointer;
border-radius: 3px;
}
.confirm {
background-color: #ddd;
}
.cancel {
background-color: rgb(252, 58, 58);
color: #fff;
}
</style>
父组件
<template>
<div class="frame">
<!-- disabled:决定是否开启传送门;to:决定传送到哪里,值为 CSS 选择器 -->
<!-- 根据 disabled 的值,决定是否将 Dialog 传送到 body 标签中 -->
<Teleport :disabled="disable" to='body'>
<Dialog @on-confirm="confirm"></Dialog>
</Teleport>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Dialog from './components/Dialog.vue';
let disable = ref(true)
const confirm = () => {
disable.value = !disable.value
console.log(disable.value)
}
</script>
<style scoped>
.frame {
position: relative;
background-color: skyblue;
height: 50vh;
}
</style>
呈现的效果就是:点击 “确定” 按钮可以切换模态框的位置