Teleport
Teleport 组件可以将内容传送到 DOM 中的其他位置,而不受组件层级的限制。这在渲染模态框、通知、全屏遮罩等需要脱离当前 DOM 层级的场景下非常有用。
基本用法
tsx
import { Teleport } from 'vitarx'
function App() {
return (
<div>
<h1>页面内容</h1>
{/* 将模态框传送到 #modal-container 中 */}
<Teleport to="#modal-container">
<div class="modal">这是一个模态框</div>
</Teleport>
</div>
)
}上面的代码中,<div class="modal"> 会被渲染到页面中 id 为 modal-container 的元素内部,而不是在当前组件的 DOM 层级中。
属性
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
children | View | 是 | — | 要传送的内容 |
to | string | 是 | — | 目标容器的 CSS 选择器 |
defer | boolean | 否 | false | 是否延迟挂载(在 onMounted 阶段挂载) |
disabled | boolean | 否 | false | 是否禁用传送,禁用时内容正常渲染在当前位置 |
to — 目标容器
to 属性支持以下选择器格式:
tsx
{
/* 传送到 id 为 modal 的元素 */
}
;<Teleport to="#modal">
<div>模态框内容</div>
</Teleport>
{
/* 传送到 body 元素 */
}
;<Teleport to="body">
<div>全屏遮罩</div>
</Teleport>
{
/* 传送到 head 元素 */
}
;<Teleport to="head">
<div>head 中的内容</div>
</Teleport>defer — 延迟挂载
默认情况下,Teleport 会在组件初始化阶段(onBeforeMount)就将内容挂载到目标容器。如果设置 defer={true},则会延迟到 onMounted 阶段挂载,确保目标容器已经存在于 DOM 中:
tsx
<Teleport to="#modal-container" defer>
<div>延迟挂载的内容</div>
</Teleport>disabled — 禁用传送
设置 disabled={true} 后,内容会正常渲染在当前位置,不会被传送到目标容器:
tsx
import { Teleport, ref } from 'vitarx'
function App() {
const isTeleported = ref(true)
return (
<div>
<button
onClick={() => {
isTeleported.value = !isTeleported.value
}}
>
{isTeleported.value ? '禁用传送' : '启用传送'}
</button>
<Teleport to="#modal-container" disabled={!isTeleported.value}>
<div class="modal">模态框内容</div>
</Teleport>
</div>
)
}注意:
to、defer、disabled属性在渲染后修改不会生效,它们只在组件初始化时读取一次。
完整示例
下面是一个模态框的完整示例,展示 Teleport 如何将模态框传送到 body 中:
tsx
import { Teleport, ref } from 'vitarx'
function Modal({
show,
onClose,
title,
children
}: {
show: { value: boolean }
onClose: () => void
title: string
children: any
}) {
return (
<Teleport to="body">
{show.value && (
<div
style="position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center;"
onClick={onClose}
>
<div
style="background: white; padding: 24px; border-radius: 8px; min-width: 300px;"
onClick={(e) => {
e.stopPropagation()
}}
>
<h2>{title}</h2>
<div>{children}</div>
<button onClick={onClose} style="margin-top: 16px;">
关闭
</button>
</div>
</div>
)}
</Teleport>
)
}
function App() {
const show = ref(false)
return (
<div>
<h1>Teleport 示例</h1>
<button
onClick={() => {
show.value = true
}}
>
打开模态框
</button>
<Modal
show={show}
onClose={() => {
show.value = false
}}
title="提示"
>
<p>这个模态框被传送到了 body 中,不受组件 DOM 层级限制。</p>
</Modal>
</div>
)
}下一步
- Suspense — 异步内容占位
- Transition — 过渡动画
- Head — 管理 document head