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。

相关推荐
变与不变8063 小时前
jQuery 核心语法与 jQuery AJAX
前端·ajax·jquery
文章永久免费只为良心3 小时前
Ctfshow_Web应用安全与防护_第二章_无字母数字命令执行
前端·python·安全·网络安全·渗透测试·ctf·红队渗透测试
小羊没烦恼!3 小时前
在.net中读写config文件的各种方法
java·大数据·运维·服务器·前端·数据库·oracle
@PHARAOH4 小时前
WHAT - Vite 8(Rolldown 底层构建引擎升级)
前端·架构
阿Q的AI笔记4 小时前
从ReAct到GRPO、从OpenHands到SWE-agent:Agent完整知识体系全拆解
前端·react.js·前端框架
计算机魔术师4 小时前
从六个月路线图到JIT规划:代码评审不只是审代码
前端
迅猛龙办公室4 小时前
Python实现PM空气质量提醒
服务器·前端·python
ydjs678899-bot4 小时前
您的Next.js中间件匹配器配置可能会跳过您认为它保护的路由
开发语言·javascript·中间件
Chengbei115 小时前
JsOwl|AI 赋能 JS 敏感信息扫描器,AST + 正则、source‑map 源码还原、登录态爬虫输出交互式 HTML 报告
开发语言·javascript·网络·人工智能·爬虫·网络安全·自动化