Vue3中新增加了一个内置组件Teleport。官网教程的叙述实在是晦涩难懂,所以我们一起研究一下teleport。这个组件的主要作用是,将模板内的 DOM 元素移动到其他位置。
teleport的使用场景:业务开发的过程中,我们经常会封装一些常用的组件,例如 Modal 组件。相信大家在使用 Modal 组件的过程中,经常会遇到一个问题,那就是 Modal 的定位问题。Teleport提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。我们只需要将弹窗内容放入Teleport内,并设置to属性为body,表示弹窗组件每次渲染都会做为body的子级,这样之前的问题就能得到解决。
例子1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const app = Vue.createApp({})
app.component('modal-button', { template: ` <button @click="modalOpen = true"> Open full screen modal!(With teleport!) </button>
<teleport to="body"> <div v-if="modalOpen" class="modal"> <div> I'm a teleported modal! (My parent is "body") <button @click="modalOpen = false">关闭</button> </div> </div> </teleport> `, data() { return { modalOpen: false } } })
app.mount('#app')
|
此时点击按钮,触发modalOpen,则会显示模态框,通过设置teleport的to到body,那么实际上这个模态框是作为body元素的子节点来显示的。
例子2:与Vue components一起使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const app = Vue.createApp({ template: ` <h1>Root instance</h1> <parent-component /> ` })
app.component('parent-component', { template: ` <h2>This is a parent component</h2> <teleport to="#endofbody"> <child-component name="John" /> </teleport> ` })
app.component('child-component', { props: ['name'], template: ` <div>Hello, </div> ` })
|
此时,就算是在不同的地方渲染的child-component,它仍然将是parent-component的子级,并将从中接收name prop。这也意味着来自父组件的注入按预期工作,并且子组件将嵌套在Vue Devtools中的父组件之下,而不是放在实际内容移动到的位置。
例子3:在同一目标上使用多个teleport
1 2 3 4 5 6 7 8 9 10 11 12
| <teleport to="#modals"> <div>A</div> </teleport> <teleport to="#modals"> <div>B</div> </teleport>
<!-- result --> <div id="modals"> //最后的形成 <div>A</div> <div>B</div> </div>
|
最常见的场景,就是是一个可重用的Modal组件,它可能同时有多个实例处于活动的状态。