uni-app 小程序支持 teleport 了

前言

在 Vue 里写弹窗、抽屉、Toast、ActionSheet 这类组件时,teleport 是非常常见的能力。它可以把内容渲染到当前组件层级之外,避免被父级的 overflow、z-index 或样式隔离影响。

但小程序不是浏览器,没有真正意义上的 document.body,也不能像 Web 一样随意移动 DOM 节点。所以以前做跨端组件时,经常需要这样写:

html 复制代码
<!-- #ifdef H5 -->
<teleport to="body">
  <popup />
</teleport>
<!-- #endif -->

<!-- #ifdef MP-WEIXIN -->
<root-portal>
  <popup />
</root-portal>
<!-- #endif -->

从 5.14 开始,小程序端支持直接写 teleport 了。开发者不再需要为了 H5 和小程序写两套条件编译,统一使用 Vue 的写法即可。

html 复制代码
<teleport to="body">
  <popup />
</teleport>

在 H5 端,它还是 Vue 原生的 teleport;在支持的小程序端,uni-app 会自动把它转换成平台原生的 root-portal。

支持平台

目前支持的平台有:

  • 微信小程序
  • 支付宝小程序
  • 京东小程序

使用方式

用法和 Vue 保持一致:

html 复制代码
<template>
  <view class="page">
    <button @click="show = true">打开弹窗</button>

    <teleport to="body">
      <view v-if="show" class="mask" @click="show = false">
        <view class="dialog" @click.stop>
          我是弹窗内容
        </view>
      </view>
    </teleport>
  </view>
</template>

<script setup>
import { ref } from 'vue'

const show = ref(false)
</script>

编译到支持的小程序平台后,模板会变成类似这样:

html 复制代码
<root-portal>
  <view class="mask">
    <view class="dialog">
      我是弹窗内容
    </view>
  </view>
</root-portal>

也就是说,开发者写的是 teleport,小程序真正运行的是 root-portal。

实现原理

这次支持本质上是一个编译期转换。

uni-app 在小程序编译阶段会识别模板里的 teleport 标签,并把它转换成 root-portal。这样既保留了 Vue 的开发体验,又能利用小程序平台已有的原生能力。

整体可以理解为:

html 复制代码
<teleport to="body">
  <view />
</teleport>

编译为:

html 复制代码
<root-portal>
  <view />
</root-portal>

需要注意的是,小程序的 root-portal 和 Vue 的 teleport 并不是完全等价的能力。Vue 的 teleport 可以通过 to 指定目标节点,而小程序的 root-portal 是把内容提升到页面根节点下渲染,并不支持传送到任意位置。

所以 uni-app 做的是能力映射,而不是在小程序里完整模拟 Web Teleport。

属性差异

虽然用法统一成了 teleport,但小程序端最终还是会落到 root-portal,所以部分属性会有差异。

to 和 defer

to 和 defer 都是 Vue Teleport 的属性,但小程序 root-portal 没有对应能力,所以编译到小程序端时会被移除。

html 复制代码
<teleport to="body" defer>
  <popup />
</teleport>

会被转换成类似:

html 复制代码
<root-portal>
  <popup />
</root-portal>

如果代码同时跑 H5 和小程序,可以继续保留这些属性:to="body" 和 defer 在 H5 端仍然有意义,只是在小程序端不会生效。

disabled

Vue Teleport 使用 disabled 控制是否禁用传送:

html 复制代码
<teleport :disabled="disabled">
  <popup />
</teleport>

小程序 root-portal 使用的是 enable,语义正好相反。因此编译到小程序时,uni-app 会自动做一次取反转换。

例如:

html 复制代码
<teleport :disabled="disabled">
  <popup />
</teleport>

会被处理成类似:

html 复制代码
<root-portal :enable="!disabled">
  <popup />
</root-portal>

开发者仍然按照 Vue 的 disabled 语义写即可,不需要手动改成 enable。

相关推荐
treasure1403 小时前
【复古】浅尝Django前后端不分离
前端·css·python·django·bootstrap·html·web
jay神4 小时前
基于 YOLOv8 的手势识别系统(Web 版)
前端·人工智能·python·深度学习·yolo·计算机视觉·计算机毕业设计
屏什么录4 小时前
长时间录屏中途崩溃:MP4 打不开的 6 种救回方案与参数设置
前端·音视频开发
ruanno_top4 小时前
表单重置后,验证码还显示已通过:Vue 受控组件的 3 种假同步
vue.js
code_Bo5 小时前
不只命令行:我把跨 Agent 会话同步做成了桌面应用
前端·javascript·后端
kyriewen5 小时前
AI 能把页面写出来,为什么改个需求就开始崩?
前端·javascript·人工智能
OpsEye5 小时前
同一套用例跑两个大模型接口,差异到底出在哪
javascript·ai编程
X1A0RAN6 小时前
PPT 图片批量处理教程:导出全部幻灯片 · 提取全部素材
开发语言·javascript·powerpoint
涛涛ing6 小时前
2026年最值得关注的前端变化,藏在“默认值”里
前端
量化分析码农7 小时前
股票历史数据的复权参数对照:多级别返回的字段与数值差异
java·javascript·后端