Vue Teleport的用法(附带实例)
Teleport 可以简单翻译为“传送,传递”,这是 Vue 3 提供的新功能。
有了 Teleport 功能,在编写代码时,开发者可以将相关的行为逻辑和UI封装到同一个组件中,提高代码的聚合性。
要明白 Teleport 功能如何使用,以及适用的场景,我们可以通过一个小例子来体会。如果我们需要开发一个全局弹窗组件,此组件自带一个触发按钮,当用户单击此按钮后,会弹出弹窗。新建一个名为 demo.teleport.html 的测试文件,在其中编写如下核心示例代码:

图 1 弹窗效果
目前看来,我们的代码运行没什么问题,但是此组件的可用性并不好,当我们在其他组件内部使用此组件时,全局弹窗的布局可能无法达到我们的预期。例如,修改 HTML 结构如下:

图 2 组件树结构影响布局
有两种方式可以避免这种由于组件树结构的改变而影响组件内元素的布局的问题:
在定义组件时,如果组件模板中的一些元素只能挂载在指定的标签下,可以使用 Teleport 来指定,可以形象地理解 Teleport 的功能是将这部分元素“传送”到指令的标签下。
以上述代码为例,可以指定全局弹窗只挂载在 body 元素下,修改代码如下:
有了 Teleport 功能,在编写代码时,开发者可以将相关的行为逻辑和UI封装到同一个组件中,提高代码的聚合性。
要明白 Teleport 功能如何使用,以及适用的场景,我们可以通过一个小例子来体会。如果我们需要开发一个全局弹窗组件,此组件自带一个触发按钮,当用户单击此按钮后,会弹出弹窗。新建一个名为 demo.teleport.html 的测试文件,在其中编写如下核心示例代码:
<div id="Application"> <my-alert></my-alert> </div> <script> const { ref } = Vue; const App = Vue.createApp({}); App.component('my-alert', { template: ` <div> <button @click="show = true">弹出弹窗</button> <div v-if="show" style=" text-align: center; padding: 20px; position: absolute; top: 45%; left: 30%; width: 40%; border: black solid 2px; background-color: white;"> <h3>弹窗</h3> <button @click="show = false">隐藏弹窗</button> </div> </div> `, setup() { const show = ref(false); return { show }; } }); App.mount('#Application'); </script>在上述代码中,我们定义了一个名为 my-alert 的组件,这个组件中默认提供了一个功能按钮,点击后会弹出弹窗,按钮和弹窗的逻辑都被聚合到了组件内部。运行代码,效果如下图所示:

图 1 弹窗效果
目前看来,我们的代码运行没什么问题,但是此组件的可用性并不好,当我们在其他组件内部使用此组件时,全局弹窗的布局可能无法达到我们的预期。例如,修改 HTML 结构如下:
<div id="Application"> <div style="position: absolute; width: 50px;"> <my-alert></my-alert> </div> </div>再次运行代码,由于当前组件被放入了一个外部的 div 元素内,因此其弹窗布局会受到影响,效果如下图所示:

图 2 组件树结构影响布局
有两种方式可以避免这种由于组件树结构的改变而影响组件内元素的布局的问题:
- 一种方式是将触发事件的按钮与全局的弹窗分成两个组件编写,保证全局弹窗组件挂载在 body 标签下,但这样会使得相关的组件逻辑分散在不同地方,不利于后续维护;
- 另一种方式是使用 Teleport。
在定义组件时,如果组件模板中的一些元素只能挂载在指定的标签下,可以使用 Teleport 来指定,可以形象地理解 Teleport 的功能是将这部分元素“传送”到指令的标签下。
以上述代码为例,可以指定全局弹窗只挂载在 body 元素下,修改代码如下:
App.component('my-alert', { template: ` <div> <button @click="show = true">弹出弹窗</button> </div> <teleport to="body"> <div v-if="show" style="text-align:center;padding:20px;position:absolute;top:30%;left:30%;width:40%;border:black solid 2px;background-color:white"> <h3>弹窗</h3> <button @click="show = false">隐藏弹窗</button> </div> </teleport> `, setup() { const show = ref(false); return { show }; } });优化后的代码,组件本身在组件树中的任何位置,弹窗都能正确地布局。