vue3-0 新特性 teleport 是啥,用起來真香

前言

vue2.0時代,我們經常會有這樣的需求,寫代碼邏輯的時候希望將組件寫在某個模板之下,因爲這樣我們很好的使用組件內部的狀態數據,控制組件的展示形態。但是從技術的角度上我們又希望將這段代碼移到DOMVue app之外的其他位置。

舉個簡單的例子,我們在使用modal組件的時候,我們將它放在了我們的模板template裏面,但是由於modal組件希望位於頁面的最上方,這時候我們將modal組件掛載在body上面是最好控制的,我們能夠很好的通過zIndex來控制modal的位置,當他嵌套在templat裏面的時候就不那麼容易了。

vue2.0 中的實現

vue2.0中我在寫這個組件的時候是通過手動的形式來進行掛載的,我寫了一個 vue 指令來進行這個操作,幫助我將modal組件掛載到body上面去,專這樣也能夠很好的通過控制zIndex來控制modal的展示。

function insert(el) {
  const parent = el.parentNode;
  if (parent && parent !== document.body) {
      parent.removeChild(el);
      document.body.appendChild(el);
  }
}

export default (typeof window !== 'undefined' ? {
  inserted(el, { value }) {
      if (value) {
          insert(el);
      }
  },
  componentUpdated(el, { value }) {
      if (value) {
          insert(el);
      }
  },
} : {});

上面的代碼其實就是簡單的將modal從他原始掛載的父節點移除,然後掛載到body上去,通過手動的形式來重新掛載,能夠很好的解決這種問題,當然上面只是簡單的邏輯,如果需要考慮卸載等其他邏輯代碼還得增加。

<template>
  <div class="modal" v-to-body="show" v-if="show">
    <div class="modal-mask" @click="close"></div>
    <slot></slot>
  </div>
</template>

<script>
import "./style.scss";
import toBody from "../directives/to-body";
export default {
  props: {
    show: Boolean,
  },
  directives: {
    toBody,
  },
  methods: {
    close() {
      this.$emit("close");
    },
  },
};
</script>

說實話vue2.0中的實現其實是沒啥問題的,只是不是很優雅,需要額外的代碼控制,所以vue3.0中直接帶來了Teleport-任意傳送門

具體代碼參考 vue2.0-modal: https://codesandbox.io/s/vue20-modal-sc1rq

什麼是 Teleport

Teleport能夠直接幫助我們將組件渲染後頁面中的任意地方,只要我們指定了渲染的目標對象。Teleport使用起來非常簡單。

<template>
  <teleport to="body" class="modal" v-if="show">
    <div class="modal-mask" @click="close"></div>
    <slot></slot>
  </teleport>
</template>

<script>
import "./style.scss";
export default {
  props: {
    show: Boolean,
  },
  methods: {
    close() {
      this.$emit("close");
    },
  },
};
</script>

上面的代碼我們就能夠很簡單的實現之前 vue2.0 所實現的功能。

具體代碼參考 vue3.0-modal: https://codesandbox.io/s/vue3-modal-x2lud

注意點

與 Vue components 一起使用

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

這也意味着來自父組件的注入按預期工作,並且子組件將嵌套在Vue Devtools中的父組件之下,而不是放在實際內容移動到的位置。

const app = Vue.createApp({
  template: `
    <h1>Root instance</h1>
    <parent-component />
  `
})

app.component('parent-component'{
  template: `
    <h2>This is a parent component</h2>
    <teleport to="#endofbody">
      <child-component  />
    </teleport>
  `
})

app.component('child-component'{
  props: ['name'],
  template: `
    <div>Hello, {{ name }}</div>
  `
})
在同一目標上使用多個 teleport

當我們將多個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>

我們可以看到對於這種情況,多個teleport組件可以將其內容掛載到同一個目標元素。順序將是一個簡單的追加——稍後掛載將位於目標元素中較早的掛載之後。

總結

一句話來描述Teleport就是一種將代碼組織邏輯依舊放在組件中,這樣我們能夠使用組件內部的數據狀態,控制組件展示的形式,但是最後渲染的地方可以是任意的,而不是侷限於組件內部

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/1UOvv3j4RuI9KzQ5mQwg8w