在这篇文章中,我们将深入探讨Vue 3引入的一个很酷的新功能--Teleport。
想通过Vue学校的免费视频课程来学习如何使用Teleport吗?
什么是 "传送"?
💡 当Vue 3还在开发中,处于测试版时,teleport被称为门户。
门户是一个来自React的著名概念,在Vue 2中也通过第三方插件如portal-vue被采用。它的名字表明,它负责把东西从一个地方 "传送 "到另一个地方......而这正是它所做的事情
有了teleport,你可以在DOM树中的不同地方渲染一个组件,即使这个地方不在你的应用程序的范围内。在处理模态、通知、弹出窗口或其他对其在DOM树中的位置敏感的元素时,远距传输非常方便。
让我告诉你
<!-- UserCard.vue -->
<template>
<div class="user-card">
<b> {{ user.name }}</b>
<button @click="isPopUpOpen = true">Remove user</button>
<div v-show="isPopUpOpen">
<p>Are you sure?</p>
<button @click="removeUser">Yes</button>
<button @click="isPopUpOpen = false">No</button>
</div>
</div>
</template>
在上面的代码例子中,我们有一个UserCard 组件,让我们从数据库中删除一个用户。点击按钮后,我们会看到一个确认弹出窗口,在这里我们可以确认该动作,并通过removeUser 方法删除该用户。
在代码维护方面,将相关的组件(确认弹出窗口)保持在同一个地方是一个很好的做法。但是当涉及到应该出现在其他元素之上的UI元素时,它可能会导致一些问题。
我们可能遇到的第一个问题是,user-card 类,以及DOM层次结构中更高的其他每一个类,都会影响我们的弹出窗口的外观。例如,如果任何一个容器有visibility: 0.5 ,那么弹出窗口的可见性就会受到影响。
保证我们的弹出窗口出现在其他组件之上是另一个挑战。你可以把DOM元素想象成层。我们把这些层放在彼此的上面来做一个布局。通常,当我们想用其他的层来覆盖一些层时,我们会有意这样做,要么把另一个元素放在这个层里面,要么放在它后面。处理这个问题的一种方法是使用z-index CSS属性来改变元素外观的自然顺序,然而,这种方法不是很优雅,通常会给我们带来另一个挑战,当我们有多个元素定位与z-index
这就是为什么我们通常把应该出现在其他元素之上的UI元素放在关闭的</body> 标签之前。这样我们就不需要做任何调整来确保我们的弹出式窗口能准确地显示在我们想要的位置和方式。它还能确保其他元素不会覆盖它。
因此,看起来我们有两个相互冲突的良好做法。
- 第一条告诉我们把相关的组件放在一起,这意味着把弹出窗口放在
UserCard组件内。 - 第二条告诉我们要把弹出窗口放在关闭的
body标签之前。
为了满足这两个要求,我们需要确保即使弹出式窗口的代码位于UserCard 组件中,它也会在其他地方呈现--最好是在关闭body 标签之前。
值得庆幸的是,这正是 teleport 的作用!
在许多新功能中,Vue 3以Teleport 组件的形式提供了对teleport的本地支持。
好消息是,Teleport 组件非常简单。它有一个属性--to 和一个默认槽。槽的内容将呈现在DOM元素中,该元素由传递给to 的查询选择器选择。
<!-- In some nested Vue component -->
<NestedComponent>
<Teleport to="#teleport-target">
<PopUp />
</Teleport>
</NestedComponent>
<!-- before closing body tag in index.html -->
<div id="teleport-target"></div>
在上面的例子中,PopUp 组件将在id为teleport-target 的div中呈现,尽管它被定位在NestedComponent 。
知道了这一点,我们就可以把我们的UserCard 组件改写成这种形式。
<!-- UserCard.vue -->
<template>
<div class="user-card">
<b> {{ user.name }}</b>
<button @click="isPopUpOpen = true">Remove user</button>
<Teleport to="#teleport-target">
<div v-show="isPopUpOpen">
<p>Are you sure?</p>
<button @click="removeUser">Yes</button>
<button @click="isPopUpOpen = false">No</button>
</div>
</Teleport>
</div>
</template>
现在,我们可以保持我们的代码的正确结构,而不需要被迫做一些讨厌的变通来保持它的工作!😉。
如果你仍然好奇,想看看其他的例子,在这里你可以找到一个带模态的小网站,使用Vue 3 teleport。你也可以在vue-next 存储库中浏览测试方案。
总结
Teleport是Vue 3中最棒的新增功能之一。它简化了对模态和弹出式窗口等元素的处理,并使其在DOM元素上的渲染变得非常容易,而不需要难看的变通方法。
