跪拜 Guibai
← Back to the summary

uni-app 5.14 Compiles Vue <teleport> Directly to Mini Program <root-portal>

Foreword

When writing components like modals, drawers, toasts, and action sheets in Vue, teleport is a very common capability. It can render content outside the current component hierarchy, preventing it from being affected by parent overflow, z-index, or style isolation.

But mini programs are not browsers; they don't have a real document.body, and you can't move DOM nodes around freely like on the Web. So previously, when building cross-platform components, you often had to write code like this:

<!-- #ifdef H5 -->
<teleport to="body">
  <popup />
</teleport>
<!-- #endif -->

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

Starting from version 5.14, mini program platforms support writing teleport directly. Developers no longer need to write two sets of conditional compilation for H5 and mini programs; they can use Vue's unified syntax.

<teleport to="body">
  <popup />
</teleport>

On the H5 side, it remains Vue's native teleport; on supported mini program platforms, uni-app automatically converts it into the platform's native root-portal.

Supported Platforms

Currently supported platforms are:

Usage

Usage is consistent with Vue:

<template>
  <view class="page">
    <button @click="show = true">Open Modal</button>

    <teleport to="body">
      <view v-if="show" class="mask" @click="show = false">
        <view class="dialog" @click.stop>
          I am the modal content
        </view>
      </view>
    </teleport>
  </view>
</template>

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

const show = ref(false)
</script>

After compiling to a supported mini program platform, the template will become something like this:

<root-portal>
  <view class="mask">
    <view class="dialog">
      I am the modal content
    </view>
  </view>
</root-portal>

In other words, the developer writes teleport, but what the mini program actually runs is root-portal.

Implementation Principle

This support is essentially a compile-time transformation.

During the mini program compilation phase, uni-app identifies the teleport tag in the template and converts it into root-portal. This preserves the Vue development experience while leveraging the existing native capabilities of the mini program platform.

Overall, it can be understood as:

<teleport to="body">
  <view />
</teleport>

Compiled to:

<root-portal>
  <view />
</root-portal>

It's important to note that the mini program's root-portal and Vue's teleport are not fully equivalent capabilities. Vue's teleport can specify a target node via to, whereas the mini program's root-portal elevates content to render under the page's root node and does not support teleporting to arbitrary positions.

So what uni-app does is capability mapping, not a complete simulation of Web Teleport within the mini program.

Attribute Differences

Although the usage is unified as teleport, the mini program side ultimately falls back to root-portal, so some attributes will differ.

to and defer

to and defer are both Vue Teleport attributes, but the mini program's root-portal has no corresponding capability, so they are removed when compiled to the mini program side.

<teleport to="body" defer>
  <popup />
</teleport>

Will be converted to something like:

<root-portal>
  <popup />
</root-portal>

If the code runs on both H5 and mini programs, you can keep these attributes: to="body" and defer still have meaning on the H5 side, they just won't take effect on the mini program side.

disabled

Vue Teleport uses disabled to control whether teleportation is disabled:

<teleport :disabled="disabled">
  <popup />
</teleport>

The mini program's root-portal uses enable, which has the opposite semantics. Therefore, when compiling to the mini program, uni-app automatically performs a negation conversion.

For example:

<teleport :disabled="disabled">
  <popup />
</teleport>

Will be processed into something like:

<root-portal :enable="!disabled">
  <popup />
</root-portal>

Developers can still write code according to Vue's disabled semantics without manually changing it to enable.

Comments

Top 2 from juejin.cn, machine-translated. The original thread is authoritative.

捷通云

uni-app is getting stronger and stronger 👏

笨笨狗吞噬者

[Like]