Vue 3 任意传送门——Teleport
2020 年 9 月 18 号,尤大大发布了 Vue 3.0
,代号 One Piece
。同时中英文版本的文档相继出来,笔者也去通读了一遍,发现很多宝藏,其中有个新特性非常吸引我——Teleport
(中文译为:传入,读着有点奇怪,本文统一以英文 Teleport
来讲)
如果用过 React
的同学,可能对于 Portals
比较熟悉,详见[1]。React 的 Portal
提供了一种将子节点渲染到存在于父组件以外的 DOM
节点的优秀的方案,我理解,Vue 3
中的 Teleport
跟这个其实是类似的
在 Vue2
,如果想要实现类似的功能,需要通过第三方库 portal-vue[2] 去实现,感兴趣可以了解一下
本篇文章主要来探讨以下两个点:
-
Teleport
是什么?它解决的是什么问题? - 通过一个小实例介绍
Teleport
的使用
为什么我们需要 Teleport
Teleport
是一种能够将我们的模板移动到 DOM
中 Vue app
之外的其他位置的技术,就有点像哆啦A梦的“任意门”
场景:像 modals
,toast
等这样的元素,很多情况下,我们将它完全的和我们的 Vue
应用的 DOM
完全剥离,管理起来反而会方便容易很多
原因在于如果我们嵌套在 Vue
的某个组件内部,那么处理嵌套组件的定位、z-index
和样式就会变得很困难
另外,像 modals
,toast
等这样的元素需要使用到 Vue
组件的状态(data
或者 props
)的值
这就是 Teleport
派上用场的地方。我们可以在组件的逻辑位置写模板代码,这意味着我们可以使用组件的 data
或 props
。然后在 Vue
应用的范围之外渲染它
Teleport 的使用
准备
快速搭建一个 vue3
的项目
$ npm init vite-app learn-vue3
$ cd learn-vue3
$ npm install
$ npm run dev
用 yarn
$ yarn create vite-app learn-vue3
$ cd learn-vue3
$ yarn
$ yarn dev
打开:http://localhost:3000/
,看到如下页面,说明成功了
toast
index.html
中
<div id="app"></div>
+ <div id="teleport-target"></div>
<script type="module" src="/src/main.js"></script>
src/components/HelloWorld.vue
中,添加如下,留意 to
属性跟上面的 id
选择器一致
<button @click="showToast" class="btn">打开 toast</button>
<!-- to 属性就是目标位置 -->
<teleport to="#teleport-target">
<div v-if="visible" class="toast-wrap">
<div class="toast-msg">我是一个 Toast 文案</div>
</div>
</teleport>
import { ref } from 'vue';
export default {
setup() {
// toast 的封装
const visible = ref(false);
let timer;
const showToast = () => {
visible.value = true;
clearTimeout(timer);
timer = setTimeout(() => {
visible.value = false;
}, 2000);
}
return {
visible,
showToast
}
}
}
效果展示:
可以看到,我们使用 teleport
组件,通过 to
属性,指定该组件渲染的位置与 <div id="app"></div>
同级,也就是在 body
下,但是 teleport
的状态 visible
又是完全由内部 Vue
组件控制
与 Vue components 一起使用 —— modal
如果 <teleport>
包含 Vue
组件,则它仍将是 <teleport>
父组件的逻辑子组件
接下来我们以一个 modal
组件为例
<div id="app"></div>
<div id="teleport-target"></div>
+ <div id="modal-container"></div>
<script type="module" src="/src/main.js"></script>
<teleport to="#modal-container">
<!-- use the modal component, pass in the prop -->
<modal :show="showModal" @close="showModal = false">
<template #header>
<h3>custom header</h3>
</template>
</modal>
</teleport>
JS 核心代码如下:
import { ref } from 'vue';
import Modal from './Modal.vue';
export default {
components: {
Modal
},
setup() {
// modal 的封装
const showModal = ref(false);
return {
showModal
}
}
}
在这种情况下,即使在不同的地方渲染 Modal
,它仍将是当前组件(调用 Modal
的组件)的子级,并将从中接收 show
prop
这也意味着来自父组件的注入按预期工作,并且子组件将嵌套在 Vue Devtools
中的父组件之下,而不是放在实际内容移动到的位置
看实际效果以及在 Vue Devtool
中
总结
本文主要介绍了 Vue 3
的新特性——Teleport
,从为什么要使用 Teleport
,以及通过两个小 demo
,演示它的基础使用,希望能够对你有帮助
本文涉及代码已全部上传到 Github[3],查看代码和效果还可以直接通过沙箱[4]
参考
- An Introduction to Vue Teleport — A New Feature in Vue3[5]
- 传入[6]
往期优秀文章推荐
- 一个合格的中级前端工程师应该掌握的 20 个 Vue 技巧[7]
- 【Vue进阶】——如何实现组件属性透传?[8]
- 前端应该知道的 HTTP 知识【金九银十必备】[9]
- 最强大的 CSS 布局 —— Grid 布局[10]
- 如何用 Typescript 写一个完整的 Vue 应用程序[11]
- 前端应该知道的web调试工具——whistle[12]
参考资料
[1]
详见: https://zh-hans.reactjs.org/docs/portals.html
[2]
portal-vue: https://github.com/LinusBorg/portal-vue
[3]
Github: https://github.com/GpingFeng/learn-vue3-teleport
[4]
沙箱: https://codesandbox.io/s/relaxed-leakey-refcv?file=/src/components/HelloWorld.vue
[5]
An Introduction to Vue Teleport — A New Feature in Vue3: https://medium.com/@mattmaribojoc/an-introduction-to-vue-teleport-a-new-feature-in-vue3-e9ddbf58dd25
[6]
传入: https://v3.cn.vuejs.org/guide/teleport.html
[7]
一个合格的中级前端工程师应该掌握的 20 个 Vue 技巧: https://juejin.im/post/6872128694639394830
[8]
【Vue进阶】——如何实现组件属性透传?: https://juejin.im/post/6865451649817640968
[9]
前端应该知道的 HTTP 知识【金九银十必备】: https://juejin.im/post/6864119706500988935
[10]
最强大的 CSS 布局 —— Grid 布局: https://juejin.im/post/6854573220306255880
[11]
如何用 Typescript 写一个完整的 Vue 应用程序: https://juejin.im/post/6860703641037340686
[12]
前端应该知道的web调试工具——whistle: https://juejin.im/post/6861882596927504392
- 通过Xtrabackup日志来恢复检查点文件
- POJ--2158--------------Milking Grid(最小覆盖字符矩阵)---(开二维kmp)
- poj-------------(2752)Seek the Name, Seek the Fame(kmp)
- hust--------The Minimum Length (最短循环节)(kmp)
- hdu-----(3746)Cyclic Nacklace(kmp)
- javaSE之如何将一个文件复制到另一个文件
- 将文件字节输出流写入到文本中
- javaSE之如何将一个文档显示出来(,txt,.doc,.....)
- Git -- 分支与合并 (命令行+可视化工具p4merge)
- java之如何实现调用启动一个可执行文件,exe
- file类之目录
- 理解Go语言Web编程(上)
- 理解Go语言Web编程(下)
- 呆呆的io流输入输出的一些基础
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java正则表达式匹配日期及基本使用
- VM虚拟机中linux centOS 联网单网卡配置教程
- Python操作redis数据库
- pytest 测试框架学习(1):初识
- 爬虫工程师也应该会的 NodeJS 知识(三)- 快速抛弃 execjs
- 八皇后问题Python实现
- 进击吧!Pythonista(6/100)
- 进击吧!Pythonista(9/100)
- 数据结构基础(一)数组,矩阵
- pytest 测试框架学习(3):pytest.approx
- pytest 测试框架学习(4):pytest.fail
- SpringBoot 开发秘籍 - 启动时配置校验
- pytest 测试框架学习(5):pytest.skip
- pytest 测试框架学习(6):pytest.importorskip
- Java 自定义注解及使用场景