<teleport>

<teleport>Vue 3 引入的新内置组件,其主要功能是可以自由定制组件内容将要渲染在页面 DOM 中的位置。举一个常见的例子,当我们需要在某段逻辑中添加一个弹窗 modal 组件,并且这个弹窗组件只有个别组件会用到时,要在设计这个弹窗组件,一般如示例代码 3-6-1 所示。

<body>
    <div id="app">
        <!--main page content here-->
    </div>
    <!--modal here-->
</body>

按照传统思路,需要将弹窗的 UI 代码放在 body 底部,然后通过原生 JavaScriptCSS 来修改 UI,这并不是很规范,并且弹窗组件的父组件没法放在使用该弹窗的组件的内部,而是必须放在根组件 #app 同级(受限于弹窗一般需要模态遮罩,该遮罩需要覆盖在完整的 body 上面并通过 CSS 样式设置)。

使用 <teleport> 则可以在当前使用者组件的代码中,将弹窗组件相关的逻辑进行引入,只需要指定渲染到哪个 DOM 节点即可,如示例代码 3-6-2 所示。

// modal.vue
<template>
    <teleport>
        <div class="modal_mask">
            <div class="modal_main">
                ...// 弹窗内容
            </div>
        </div>
    </teleport>
</template>

// use.vue
<template>
    <div>子组件User</div>
    <modal/>
</template>

如上面的代码所示,将弹窗内容放入 <teleport> 内,并设置 to 属性为 body,表示弹窗组件每次渲染都会作为 body 的子级,这样之前的问题就能得到解决。

<teleport> 组件接收两个 props,第一个 to 是字符串类型,表示将要渲染的节点选择器,支持常用的 CSS 选择器,代码如下:

<!-- 正确 -->
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />
<!-- 错误 -->
<teleport to="h1" />
<teleport to="some-string" />

第二个 propsdisabled,布尔类型,表示禁用 <teleport> 的功能,这意味着 <teleport> 将内容将保留在其原始位置,而不是用户在周围父组件中指定了 <teleport> 的位置渲染。

多个 <teleport> 可以指定同一个 DOM 节点,顺序是简单地追加,后面渲染的内容将会在之前渲染的内容之后,代码如下:

<teleport to="#modals">
<div>A</div>
</teleport>
<teleport to="#modals">
<div>B</div>
</teleport>
<!-- 结果-->
<div id="modals">
<div>A</div>
<div>B</div>
</div>

总之,<teleport> 内置组件在代码层面提供了一种很便捷的方法,允许我们控制在 DOM 中哪个父节点下渲染 HTML,而不必求助于全局状态或原生 JavaScript 来设置内容这种蹩脚的写法。