可复用 & 组合--④:Teleport

425 阅读1分钟

Teleport

基本用法

Teleport 提供了一种方法,允许我们控制在 DOM 中哪个父节点下渲染 HTML

默认情况下

<body>
  <div id="app">
    <my-component></my-component>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.component("my-component", {
      name: "my-component",
      template: `
        <div>
          my-component
        </div>
    `,
    });

    app.mount("#app");
  </script>
</body>

可以看到默认情况下组件被嵌套在 div 中。


渲染到指定的父节点下

<body>
  <div id="app">
    <my-component></my-component>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.component("my-component", {
      name: "my-component",
      template: `
        <teleport to="body">
          <div>
            my-component
          </div>
        </teleport>
      `,
    });

    app.mount("#app");
  </script>
</body>

现在,通过 Teleport 使组件渲染为 body 标签的子节点。


与 Vue components 一起使用

未使用 Teleport 情况下

<body>
  <div id="app">
    <parent-component></parent-component>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.component("parent-component", {
      name: "parent-component",
      template: `
        <div>
          <p>parent-component</p>
          <child-component></child-component>
        </div>
      `,
    });

    app.component("child-component", {
      name: "child-component",
      template: `
        <div>
          <p>child-component</p>
        </div>
      `,
    });

    app.mount("#app");
  </script>
</body>

在未使用 Teleport 情况下,子组件嵌套在父组件中。


使用 Teleport 情况下

<body>
  <div id="app">
    <parent-component></parent-component>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.component("parent-component", {
      name: "parent-component",
      template: `
        <div>
          <p>parent-component</p>
          <teleport to="#app">
            <child-component></child-component>  
          </teleport>
        </div>
      `,
    });

    app.component("child-component", {
      name: "child-component",
      template: `
        <div>
          <p>child-component</p>
        </div>
      `,
    });

    app.mount("#app");
  </script>
</body>

可以看到,我们使用 Teleport,通过 to 属性,指定子组件渲染的位置与父组件同级 。


在这种情况下,即使在不同的地方渲染子组件,但它仍是父组件的子级,并将从中接收 age

<body>
  <div id="app">
    <parent-component></parent-component>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.component("parent-component", {
      name: "parent-component",
      template: `
        <div>
          <p>parent-component</p>
          <teleport to="#app">
            <child-component age="18"></child-component>  
          </teleport>
        </div>
      `,
    });

    app.component("child-component", {
      name: "child-component",
      template: `
        <div>
          <p>child-component: {{ age }}</p>
        </div>
      `,
      props: ["age"]
    });

    app.mount("#app");
  </script>
</body>

在同一目标上使用多个 teleport

可以将多个 <teleport> 组件挂载到同一个目标元素。顺序是简单的追加---先来的先挂载。

<body>
  <div id="app">
    <div id="target"></div>

    <teleport to="#target">
      <div>A</div>
    </teleport>

    <teleport to="#target">
      <div>B</div>
    </teleport>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.mount("#app");
  </script>
</body>

1628756951705.png

但要注意一点:标签 <teleport> 属性 to 指向的 DOM 元素要先存在,不然 <teleport> 组件渲染不出来。

<body>
  <div id="app">
    <teleport to="#target">
      <div>A</div>
    </teleport>

    <teleport to="#target">
      <div>B</div>
    </teleport>

    <div id="target"></div>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.mount("#app");
  </script>
</body>

像这个例子,元素 <div id="target"></div><teleport> 之后渲染,导致无法找到目标,从而渲染失败。