对于teleport组件,我们先来看一下官方是怎么说的吧。

Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下渲染了 HTML,而不必求助于全局状态或将其拆分为两个组件。 简单的来说就是teleport可以控制在哪一个dom上去渲染你的组件,去解决一些使用组件时受到父元素样式影响的问题。

直接来看一个例子吧。我们写一个modal弹窗的组件。点击按钮使其出现,再次点击使其关闭。

Modal.vue

<template>
  <div id="modal">
    <h2>这是一个modal</h2>
  </div>
</template>
<script lang="ts">
export default {};
</script>
<style>
#modal {
  width: 200px;
  height: 200px;
  border: 2px solid black;
  background: white;
  position: fixed;
  left: 50%;
  top: 50%;
  margin-left: -100px;
  margin-top: -100px;
}
</style>

TeleportCom.vue

<template>
  <div class="teleport-com">
    <button @click="showModal">{{ show ? "隐藏" : "显示" }}</button>
    <Modal v-if="show" />
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
import Modal from "@/components/Modal.vue";
export default defineComponent({
  name: "teleport-com",
  components: {
    Modal,
  },
  setup() {
    const data = reactive({
      show: false,
      showModal: () => {
        data.show = !data.show;
      },
    });
    const refData = toRefs(data);
    return {
      ...refData,
    };
  },
});
</script>
<style lang="scss" scoped>
.teleport-com {
}
</style>

来看一下效果

alt

会发现没有在Modal.vue组件写文字居中,但是文字居中了。这是由于Modal组件渲染在了app节点中,受到了app节点样式的影响。 alt alt

我们怎么在不修改Modal组件上的前提上解决这个问题了,teleport提供了解决方案。

  1. 修改index.html,新增一个id为modal-container的div
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong
        >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
        properly without JavaScript enabled. Please enable it to
        continue.</strong
      >
    </noscript>
    <div id="app"></div>
    // 新增一个id为modal-container的div
    <div id="modal-container"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

  1. 修改Modal.vue组件,使用teleport组件包裹

    查看效果,样式不受到app节点控制,且不在渲染在app节点中 alt alt

    1. 或者我们还能这样改,重用性更强。把Modal.vue还原为文章最初的样子,修改TeleportCom.vue,使用teleport直接包裹使用的组件
    <template>
      <div class="teleport-com">
        <button @click="showModal">{{ show ? "隐藏" : "显示" }}</button>
        // 使用`teleport`直接包裹使用的组件
        <teleport to="#modal-container">
          <Modal v-if="show" />
        </teleport>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, reactive, toRefs } from "vue";
    import Modal from "@/components/Modal.vue";
    export default defineComponent({
      name: "teleport-com",
      components: {
        Modal,
      },
      setup() {
        const data = reactive({
          show: false,
          showModal: () => {
            data.show = !data.show;
          },
        });
        const refData = toRefs(data);
        return {
          ...refData,
        };
      },
    });
    </script>
    <style lang="scss" scoped>
    .teleport-com {
    }
    </style>
    
    

    可以看到也是一样的效果哟

    alt

    alt