Vue 3.0 Teleport

2022-03-08 17:05 更新

Vue 鼓勵我們通過將 UI 和相關(guān)行為封裝到組件中來構(gòu)建 UI。我們可以將它們嵌套在另一個內(nèi)部,以構(gòu)建一個組成應(yīng)用程序 UI 的樹。

然而,有時組件模板的一部分邏輯上屬于該組件,而從技術(shù)角度來看,最好將模板的這一部分移動到 DOM 中 Vue app 之外的其他位置。

一個常見的場景是創(chuàng)建一個包含全屏模式的組件。在大多數(shù)情況下,你希望模態(tài)框的邏輯存在于組件中,但是模態(tài)框的快速定位就很難通過 CSS 來解決,或者需要更改組件組合。

考慮下面的 HTML 結(jié)構(gòu)。

  1. <body>
  2. <div style="position: relative;">
  3. <h3>Tooltips with Vue 3 Teleport</h3>
  4. <div>
  5. <modal-button></modal-button>
  6. </div>
  7. </div>
  8. </body>

讓我們來看看 modal-button 組件:

該組件將有一個 button 元素來觸發(fā)模態(tài)的打開,以及一個具有類 .modaldiv 元素,它將包含模態(tài)的內(nèi)容和一個用于自關(guān)閉的按鈕。

  1. const app = Vue.createApp({});
  2. app.component('modal-button', {
  3. template: `
  4. <button @click="modalOpen = true">
  5. Open full screen modal!
  6. </button>
  7. <div v-if="modalOpen" class="modal">
  8. <div>
  9. I'm a modal!
  10. <button @click="modalOpen = false">
  11. Close
  12. </button>
  13. </div>
  14. </div>
  15. `,
  16. data() {
  17. return {
  18. modalOpen: false
  19. }
  20. }
  21. })

當(dāng)在初始的 HTML 結(jié)構(gòu)中使用這個組件時,我們可以看到一個問題——模態(tài)是在深度嵌套的 div 中渲染的,而模態(tài)的 position:absolute 以父級相對定位的 div 作為引用。

Teleport 提供了一種干凈的方法,允許我們控制在 DOM 中哪個父節(jié)點下呈現(xiàn) HTML,而不必求助于全局狀態(tài)或?qū)⑵洳鸱譃閮蓚€組件。

讓我們修改 modal-button 以使用 <teleport>,并告訴 Vue “Teleport 這個 HTML 該‘body’標(biāo)簽”。

  1. app.component('modal-button', {
  2. template: `
  3. <button @click="modalOpen = true">
  4. Open full screen modal! (With teleport!)
  5. </button>
  6. <teleport to="body">
  7. <div v-if="modalOpen" class="modal">
  8. <div>
  9. I'm a teleported modal!
  10. (My parent is "body")
  11. <button @click="modalOpen = false">
  12. Close
  13. </button>
  14. </div>
  15. </div>
  16. </teleport>
  17. `,
  18. data() {
  19. return {
  20. modalOpen: false
  21. }
  22. }
  23. })

因此,一旦我們單擊按鈕打開模式,Vue 將正確地將模態(tài)內(nèi)容渲染為 body 標(biāo)簽的子級。

點擊此處實現(xiàn)

#與 Vue components 一起使用

如果 <teleport> 包含 Vue 組件,則它仍將是 <teleport> 父組件的邏輯子組件:

  1. const app = Vue.createApp({
  2. template: `
  3. <h1>Root instance</h1>
  4. <parent-component />
  5. `
  6. })
  7. app.component('parent-component', {
  8. template: `
  9. <h2>This is a parent component</h2>
  10. <teleport to="#endofbody">
  11. <child-component name="John" />
  12. </teleport>
  13. `
  14. })
  15. app.component('child-component', {
  16. props: ['name'],
  17. template: `
  18. <div>Hello, {{ name }}</div>
  19. `
  20. })

在這種情況下,即使在不同的地方渲染 child-component,它仍將是 parent-component 的子級,并將從中接收 name prop。

這也意味著來自父組件的注入按預(yù)期工作,并且子組件將嵌套在 Vue Devtools 中的父組件之下,而不是放在實際內(nèi)容移動到的位置。

#在同一目標(biāo)上使用多個 teleport

一個常見的用例場景是一個可重用的 <Modal> 組件,它可能同時有多個實例處于活動狀態(tài)。對于這種情況,多個 <teleport> 組件可以將其內(nèi)容掛載到同一個目標(biāo)元素。順序?qū)⑹且粋€簡單的追加——稍后掛載將位于目標(biāo)元素中較早的掛載之后。

  1. <teleport to="#modals">
  2. <div>A</div>
  3. </teleport>
  4. <teleport to="#modals">
  5. <div>B</div>
  6. </teleport>
  7. <!-- result-->
  8. <div id="modals">
  9. <div>A</div>
  10. <div>B</div>
  11. </div>

你可以在 API 參考 查看 teleport 組件。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號