前言
本笔记主要基于官方文档《Vue 3 教程-Teleort》汇总而来。如有理解出入,请以官方文档为主。建议您以官方文档为主,本文为辅。这样您可以“以自己为主”审视的阅读,从而不被我的观点带偏。
什么是 Teleport ?
Teleport 是 Vue 3.x 新增自定义元素,借助 Teleport 可以控制 Teleport 内部的内容挂载到具体的元素中。
场景模拟
我们先看这样的一个场景
在一个多层嵌套的组件中,我们构建了一个模态框。我们想要这个模态框相对于最顶层的元素显示,该怎么做呢?
常见的解决方法有:
- 设置CSS属性
。让模态框相对于浏览器窗口进行定位。
position:fixed;
- 设置CSS属性
和
position:relative;
。让设置了
position:absolute;
的元素相对于
position:absolute;
属性进行定位。但是这个方法有个缺点:两者必须是嵌套关系,而且中间直系层级不能存在其他设置了
position:relative;
或
position:relative;
的元素。
position:absolute;
换一个场景,如果模态框是相对于其具体的某个父辈元素显示呢?
这时我们就只能采用第二种方法了。而第二种方法的缺点我们刚刚也说了。
面对上面两种情景,这时我们可能就会想:“如果
position:relative;
元素和
position:absolute;
元素的相对关系不被其他设置了
position:relative;
或
position:absolute;
的元素影响就好了。”
Vue 3.x 有吗?Teleport 是不是就是用来实现了这个功能?
很遗憾!Vue 3.x 并没解决“
position:relative;
元素和
position:absolute;
元素的相对关系被其他设置了
position:relative;
或
position:absolute;
的元素影响”这个问题。
Teleport 的原理
注意:这里并不是讲解 Teleport 的底层代码。仅仅是说明的其背后的逻辑。
首先,Teleport 并没有解决
position:relative;
与
position:absolute;
的弊端。但是Vue 3.x 换了一个思路来解决这个问题。
position:relative;
与 position:absolute;
的弊端无法解决
position:relative;
position:absolute;
就算Vue 再强大,它都是基于 HTML+CSS+JavaScript 三者来构建的。
position:relative;
与
position:absolute;
关系是CSS创建之时已经固定,是 Vue 世界的“世界准则”,无法改变。Vue 只是基于这些准则构建起来的一个“世界”,故无法改变。
让 position:relative;
与 position:absolute;
之间的元素消失
position:relative;
position:absolute;
既然无法改变,那我们就要寻找“准则”的漏洞。
既然中间的元素可能影响到
position:relative;
元素与
position:absolute;
元素的相对关系。那如果我们让中间元素消失是不是就可以解决这个问题呢?
没错,这就是 Teleport 的最基本的思路。Vue 3.x 是怎么做呢?
Vue 3.x 并不是删除中间的元素,而是将
position:absolute;
元素从原本的位置移动到
position:relative;
元素内部,作为
position:relative;
元素的子元素(注意区分子元素和子孙元素)。这样子,他们之间就不存在其他元素了。
请注意,Teleport 是移动 DOM 节点,而不是被销毁和重新创建,并且它还将保持任何组件实例的活动状态。所有有状态的 HTML 元素 (即播放的视频) 都将保持其状态。
小结
以上就算对 Teleport 用途的讲解。概括来讲:借助 Teleport,我们可以控制一段 HTML 代码在 Vue Document 中的任何一个地方显示渲染。上面的情景模拟仅仅是 Teleport 的一种用途,请不要拘泥于此。
Teleport 的Props参数
属性 | 数据类型 | 必要 | 说明 |
---|---|---|---|
| | 必填 | 用于指定一个目标元素将 Teleport 内容移动到其中。必须是有效的CSS选择器 |
| | 可选 | 用于禁用 的功能,这意味着其插槽内容将不会移动到任何位置 |
举例:
<!-- to 正确用法 -->
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />
<!-- to 错误用法 -->
<teleport to="h1" />
<teleport to="some-string" />
<!-- disabled 用法 -->
<teleport to="#popup" :disabled="displayVideoInline">
<video src="./my-movie.mp4">
</teleport>
在组件中使用 Teleport
前面我们说到,Teleport 可以将其内部的内容移动到目标元素内部,并充当目标元素的子元素。这个目标元素可以是当前组件内的也可以是组件外部的。
这时可能大家机会疑惑?如果移动到外部,那当前组件是否还可以操作移出去的那部分元素呢?
不用担心,我们依旧可以像往常一样操作。如下官方的例子:
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, {{ name }}</div>
`
})
在这种情况下,即使在不同的地方渲染
child-component
,它仍将是
parent-component
的子级,并将从中接收
name
prop。
这也意味着来自父组件的注入按预期工作,并且子组件将嵌套在 Vue Devtools 中的父组件之下,而不是放在实际内容移动到的位置。
在同一目标上使用多个 Teleport
多个
<teleport>
组件可以将其内容挂载到同一个目标元素。顺序将是一个简单的追加——稍后挂载将位于目标元素中较早的挂载之后。
<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>
参考文档
本系列目录
- Vue 3 迁移策略笔记—— 第1节:v-for 中的 Ref 数组
- Vue 3 迁移策略笔记—— 第2节:Async Components 异步组件
- Vue 3 迁移策略笔记—— 第3节:Attribute Coercion Behavior (属性强制行为)
- Vue 3 迁移策略笔记——第4节:$attrs 包括class&style
- Vue 3 迁移策略笔记—— 第5节:移除 $children
- Vue 3 迁移策略笔记—— 第6节:自定义指令
- Vue 3 迁移策略笔记—— 第7节:自定义元素交互
- Vue 3 迁移策略笔记—— 第8节:Data 选项
- Vue 3 迁移策略笔记—— 第9节:新增 emits 选项
- Vue 3 迁移策略笔记—— 第10节:事件 API
- Vue 3 迁移策略笔记—— 第11节:移除过滤器
- Vue 3 迁移策略笔记—— 第12节:片段
- Vue 3 迁移策略笔记—— 第13节:函数式组件
- Vue 3 迁移策略笔记—— 第14节:全局 API
- Vue 3 迁移策略笔记—— 第15节:全局 API 的 tree shaking
- Vue 3 迁移策略笔记—— 第16节:Inline Template 属性
- Vue 3 迁移策略笔记—— 第17节:Key 属性
- Vue 3 迁移策略笔记—— 第18节:按键修饰符
- Vue 3 迁移策略笔记—— 第19节:移除 $listeners
- Vue 3 迁移策略笔记—— 第20节:Props 的默认值函数不能访问this
- Vue 3 迁移策略笔记—— 第21节:渲染函数 API
- Vue 3 迁移策略笔记—— 第22节:Slots 的统一
- Vue 3 迁移策略笔记—— 第23节:Transition Class 的变化
- Vue 3 迁移策略笔记—— 第24节:Transition Group 不再需要设置根元素
- Vue 3 迁移策略笔记—— 第25节:v-on.native修饰符被移除
- Vue 3 迁移策略笔记—— 第26节:在组件上使用 v-model 的变化
- Vue 3 迁移策略笔记—— 第27节:v-if 和 v-for 的优先级
- Vue 3 迁移策略笔记—— 第28节:v-bind 合并行为
- Vue 3 迁移策略笔记—— 第29节:数组的监听
- Vue 3 迁移策略笔记—— 第30节:新增功能——Teleport