对于teleport
组件,我们先来看一下官方是怎么说的吧。
Teleport
提供了一种干净的方法,允许我们控制在DOM
中哪个父节点下渲染了HTML
,而不必求助于全局状态或将其拆分为两个组件。 简单的来说就是teleport
可以控制在哪一个dom
上去渲染你的组件,去解决一些使用组件时受到父元素样式影响的问题。
直接来看一个例子吧。我们写一个modal弹窗的组件。点击按钮使其出现,再次点击使其关闭。
Modal.vue
<template>
<div id="modal">
<h2>这是一个modal</h2>
</div>
</template>
<script lang="ts">
export default {};
</script>
<style>
#modal {
width: 200px;
height: 200px;
border: 2px solid black;
background: white;
position: fixed;
left: 50%;
top: 50%;
margin-left: -100px;
margin-top: -100px;
}
</style>
TeleportCom.vue
<template>
<div class="teleport-com">
<button @click="showModal">{{ show ? "隐藏" : "显示" }}</button>
<Modal v-if="show" />
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
import Modal from "@/components/Modal.vue";
export default defineComponent({
name: "teleport-com",
components: {
Modal,
},
setup() {
const data = reactive({
show: false,
showModal: () => {
data.show = !data.show;
},
});
const refData = toRefs(data);
return {
...refData,
};
},
});
</script>
<style lang="scss" scoped>
.teleport-com {
}
</style>
来看一下效果
会发现没有在Modal.vue
组件写文字居中,但是文字居中了。这是由于Modal
组件渲染在了app
节点中,受到了app
节点样式的影响。
我们怎么在不修改Modal
组件上的前提上解决这个问题了,teleport
提供了解决方案。
- 修改
index.html
,新增一个id为modal-container
的div
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div>
// 新增一个id为modal-container的div
<div id="modal-container"></div>
<!-- built files will be auto injected -->
</body>
</html>
- 修改
Modal.vue
组件,使用teleport
组件包裹// 使用teleport组件包裹
这是一个modal
查看效果,样式不受到app节点控制,且不在渲染在app节点中
- 或者我们还能这样改,重用性更强。把Modal.vue还原为文章最初的样子,修改
TeleportCom.vue
,使用teleport
直接包裹使用的组件
<template> <div class="teleport-com"> <button @click="showModal">{{ show ? "隐藏" : "显示" }}</button> // 使用`teleport`直接包裹使用的组件 <teleport to="#modal-container"> <Modal v-if="show" /> </teleport> </div> </template> <script lang="ts"> import { defineComponent, reactive, toRefs } from "vue"; import Modal from "@/components/Modal.vue"; export default defineComponent({ name: "teleport-com", components: { Modal, }, setup() { const data = reactive({ show: false, showModal: () => { data.show = !data.show; }, }); const refData = toRefs(data); return { ...refData, }; }, }); </script> <style lang="scss" scoped> .teleport-com { } </style>
可以看到也是一样的效果哟
- 或者我们还能这样改,重用性更强。把Modal.vue还原为文章最初的样子,修改