淺析Vue3新特性-Teleport(任意傳送門也稱瞬間移動):為什么需要Teleport、與React的Portals特性、如何使用(直接使用、與組件搭配使用、使用多個teleport)、teleport API(to及disabled使用介紹)


  Teleport 是什么?它解決的是什么問題?

一、使用場景 - 為什么我們需要 Teleport

  Teleport 是一種能夠將我們的模板移動到 DOMVue app 之外的其他位置的技術。

1、使用場景:

  業務開發的過程中,我們經常會封裝一些常用的組件,例如 Modal 組件。相信大家在使用 Modal 組件的過程中,經常會遇到一個問題,那就是 Modal 的定位問題。

(1)像 modalstoast 等這樣的元素,很多情況下,我們將它完全的和我們的 Vue 應用的 DOM 完全剝離,管理起來反而會方便容易很多。原因在於如果我們嵌套在 Vue 的某個組件內部,那么處理嵌套組件的定位、z-index 和樣式就會變得很困難。

(2)另外,像 modalstoast 等這樣的元素需要使用到 Vue 組件的狀態(data 或者 props)的值。

2、作用 - 這就是 Teleport 派上用場的地方:

  我們可以在組件的邏輯位置寫模板代碼,這意味着我們可以使用組件的 dataprops,然后在 Vue 應用的范圍之外渲染它

Teleport 提供了一種干凈的方法,允許我們控制在 DOM 中哪個父節點下呈現 HTML,而不必求助於全局狀態或將其拆分為兩個組件。 -- Vue 官方文檔
3、多個 <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>

二、React 的 Portals 特性

  介紹了 Teleport 之后我們也來了解一下 React 的 Portals 特性。Portal 提供了一種將子節點渲染到存在於父組件以外的 DOM 節點的優秀的方案。

ReactDOM.createPortal(child, container)

  第一個參數(child)是任何可渲染的 React 子元素,例如一個元素,字符串或 fragment。第二個參數(container)是一個 DOM 元素。

  通常來講,當你從組件的 render 方法返回一個元素時,該元素將被掛載到 DOM 節點中離其最近的父節點。
render() { // React 掛載了一個新的 div,並且把子元素渲染其中
  return ( <div> {this.props.children} </div> ); }

  然而,有時候將子元素插入到 DOM 節點中的不同位置也是有好處的:

render() { // React 並沒有創建一個新的 div。它只是把子元素渲染到 `domNode` 中。 // `domNode` 是一個可以在任何位置的有效 DOM 節點。
  return ReactDOM.createPortal( this.props.children, domNode ); }

  一個 portal 的典型用例是當父組件有 overflow: hidden 或 z-index 樣式時,但你需要子組件能夠在視覺上“跳出”其容器。例如,對話框、懸浮卡以及提示框。常見的情況是創建一個包含全屏模式的組件。

  對話框 position: absolute 的定位相對於父 div 作為參考。Teleport 提供了一種簡單的方法,使我們可以控制要在DOM中哪個父對象下呈現HTML。

三、Teleport 使用

1、代碼示例:直接使用

// 1、index.html 中,我們加一個和 app 同級的 div
<div id="app"></div>
<div id="teleport-target"></div>
// 2、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>
// 3、再使用 js 我們使用組件里的 變量 去控制 toast 顯示隱藏
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 組件:

(1)通過 to 屬性,指定該組件渲染的位置與 <div id="app"></div> 同級,也就是在 body 下,

(2)但是 teleport狀態 visible 又是完全由內部 Vue 組件控制

2、代碼示例:與 Vue 組件一起使用 - modal

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

<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> import { ref } from 'vue'; import Modal from './Modal.vue'; export default { components: { Modal }, setup() { // modal 的封裝
    const showModal = ref(false); return { showModal } } }

  在這種情況下,即使在不同的地方渲染 Modal,它仍將是當前組件(調用 Modal 的組件)的子級,並將從中接收 prop,這也意味着來自父組件的注入按預期工作,並且子組件將嵌套在 Vue Devtools 中的父組件之下,而不是放在實際內容移動到的位置。

3、在同一目標上使用多個teleport

  一個常見的用例場景是一個可重用的<Modal>組件,它可能同時有多個實例處於活動狀態。

四、Teleport API

1、to - string,需要prop,必須是有效的查詢選擇器或HTMLElement(如果在瀏覽器環境中使用)。指定將在其中一棟<teleport>內容的目標元素

2、disabled - boolean,此可選屬性可用於禁用<teleport>的功能,這意味着其插槽內容將不會移動到任何位置,而是在您在周圍父組件中指定了<teleport>的位置渲染。

<teleport to="#popup" :disabled="displayVideoInline">
    <video src="./my-movie.mp4">
</teleport>

  請注意,這將移動實際的DOM節點,而不是被銷毀和重新創建,並且它還將保持任何組件實例的活動狀態。所有有狀態的HTML元素(即播放的視頻)都將保持其狀態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM