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"> 会被渲染到页面中 idmodal-container 的元素内部,而不是在当前组件的 DOM 层级中。

属性

属性类型必填默认值说明
childrenView要传送的内容
tostring目标容器的 CSS 选择器
deferbooleanfalse是否延迟挂载(在 onMounted 阶段挂载)
disabledbooleanfalse是否禁用传送,禁用时内容正常渲染在当前位置

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>
  )
}

注意todeferdisabled 属性在渲染后修改不会生效,它们只在组件初始化时读取一次。

完整示例

下面是一个模态框的完整示例,展示 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>
  )
}

下一步