
2020 年 9 月 18 號(hào),尤大大發(fā)布了 Vue 3.0,代號(hào) One Piece。同時(shí)中英文版本的文檔相繼出來(lái),筆者也去通讀了一遍,發(fā)現(xiàn)很多寶藏,其中有個(gè)新特性非常吸引我——Teleport(中文譯為:傳入,讀著有點(diǎn)奇怪,本文統(tǒng)一以英文 Teleport 來(lái)講)

如果用過(guò) React 的同學(xué),可能對(duì)于 Portals 比較熟悉,詳見(jiàn)。React 的 Portal 提供了一種將子節(jié)點(diǎn)渲染到存在于父組件以外的 DOM 節(jié)點(diǎn)的優(yōu)秀的方案,我理解,Vue 3 中的 Teleport 跟這個(gè)其實(shí)是類似的
在 Vue2,如果想要實(shí)現(xiàn)類似的功能,需要通過(guò)第三方庫(kù) portal-vue 去實(shí)現(xiàn),感興趣可以了解一下
本篇文章主要來(lái)探討以下兩個(gè)點(diǎn):
-
Teleport是什么?它解決的是什么問(wèn)題? - 通過(guò)一個(gè)小實(shí)例介紹
Teleport的使用
為什么我們需要 Teleport
Teleport 是一種能夠?qū)⑽覀兊哪0逡苿?dòng)到 DOM 中 Vue app 之外的其他位置的技術(shù),就有點(diǎn)像哆啦A夢(mèng)的“任意門”
場(chǎng)景:像 modals,toast 等這樣的元素,很多情況下,我們將它完全的和我們的 Vue 應(yīng)用的 DOM 完全剝離,管理起來(lái)反而會(huì)方便容易很多
原因在于如果我們嵌套在 Vue 的某個(gè)組件內(nèi)部,那么處理嵌套組件的定位、z-index 和樣式就會(huì)變得很困難
另外,像 modals,toast 等這樣的元素需要使用到 Vue 組件的狀態(tài)(data 或者 props)的值
這就是 Teleport 派上用場(chǎng)的地方。我們可以在組件的邏輯位置寫(xiě)模板代碼,這意味著我們可以使用組件的 data 或 props。然后在 Vue 應(yīng)用的范圍之外渲染它
Teleport 的使用
準(zhǔn)備
快速搭建一個(gè) vue3 的項(xiàng)目
$ 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
打開(kāi): http://localhost:3000/,看到如下頁(yè)面,說(shuō)明成功了

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">打開(kāi) toast</button>
<!-- to 屬性就是目標(biāo)位置 -->
<teleport to="#teleport-target">
<div v-if="visible" class="toast-wrap">
<div class="toast-msg">我是一個(gè) 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 組件,通過(guò) to 屬性,指定該組件渲染的位置與 <div id="app"></div> 同級(jí),也就是在 body 下,但是 teleport 的狀態(tài) visible 又是完全由內(nèi)部 Vue 組件控制
與 Vue components 一起使用 —— modal
如果 <teleport> 包含 Vue 組件,則它仍將是 <teleport> 父組件的邏輯子組件
接下來(lái)我們以一個(gè) 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,它仍將是當(dāng)前組件(調(diào)用 Modal 的組件)的子級(jí),并將從中接收 show prop
這也意味著來(lái)自父組件的注入按預(yù)期工作,并且子組件將嵌套在 Vue Devtools 中的父組件之下,而不是放在實(shí)際內(nèi)容移動(dòng)到的位置
看實(shí)際效果以及在 Vue Devtool 中

總結(jié)
本文主要介紹了 Vue 3 的新特性——Teleport,從為什么要使用 Teleport,以及通過(guò)兩個(gè)小 demo,演示它的基礎(chǔ)使用,希望能夠?qū)δ阌袔椭?/p>
本文涉及代碼已全部上傳到 Github,查看代碼和效果還可以直接通過(guò)沙箱