Vue 3 任意傳送門——Teleport

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)到 DOMVue 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ě)模板代碼,這意味著我們可以使用組件的 dataprops。然后在 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ò)沙箱

參考

往期優(yōu)秀文章推薦

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容