Skip to content

虚拟根组件

说明

本文档适用于 uView Pro 0.6.12 及以上版本,内置了虚拟根组件能力,无需额外安装第三方插件。

解决的问题

UniApp 不支持原生的根组件包裹机制,导致无法在全局统一注入 u-config-provideru-toastu-modal 等需要在每个页面根部存在的组件。传统方案需要在每个页面手动添加,维护成本高。

uView Pro 内置了虚拟根组件 Vite 插件,通过构建时自动为每个页面注入全局根组件,无需修改任何页面代码。

使用方式

1. 创建 App.root.vue

src/ 目录下创建 App.root.vue 文件:

vue
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app';
import { useTheme, useLocale } from 'uview-pro';

const { darkMode, themes, currentTheme } = useTheme();
const { currentLocale } = useLocale();

onLoad(() => {
    console.log('darkMode->', darkMode.value);
    console.log('theme->', currentTheme.value?.name);
    console.log('locale->', currentLocale.value?.name);
});
</script>

<template>
    <u-config-provider>
        <slot />
        <u-toast global></u-toast>
        <u-modal global></u-modal>
    </u-config-provider>
</template>

注意

<slot /> 是页面内容的渲染位置,必须保留。页面内容会通过插槽传入并渲染在此处。

2. 配置 vite.config.ts

ts
import { defineConfig } from 'vite';
import Uni from '@dcloudio/vite-plugin-uni';
import { UniRoot } from 'uview-pro/plugins';

export default defineConfig({
    plugins: [
        UniRoot(), // 放在其他插件之前
        Uni(),
    ],
});
ts
import { defineConfig } from 'vite';
import Uni from '@dcloudio/vite-plugin-uni';
import { UniRoot } from './src/uni_modules/uview-pro/plugins';

export default defineConfig({
    plugins: [
        UniRoot(), // 放在其他插件之前
        Uni(),
    ],
});

提示

若存在改变 pages.json 的插件,请将 UniRoot 放置其后。

3. 运行

bash
npm run dev

不需要修改任何页面代码,所有页面会自动被 <global-root-view> 包裹,App.root.vue 中的内容全局生效。

常见使用场景

全局主题与暗黑模式

配合 u-config-provideruseTheme,实现全局主题切换:

vue
<!-- App.root.vue -->
<template>
    <u-config-provider>
        <slot />
    </u-config-provider>
</template>

详见 多主题与暗黑模式

全局 Toast 和 Modal

App.root.vue 中挂载全局组件,任意页面均可调用:

vue
<!-- App.root.vue -->
<template>
    <slot />
    <u-toast global></u-toast>
    <u-modal global></u-modal>
</template>

页面中通过组合式 API 调用:

ts
import { useToast, useModal } from 'uview-pro';

const toast = useToast();
const modal = useModal();

toast.show('操作成功');
modal.confirm({ content: '确认删除?' });

全局 Loading

vue
<!-- App.root.vue -->
<template>
    <slot />
    <u-loading-popup v-model="show" />
</template>

配置项

ts
UniRoot({
    rootFileName: 'App.root', // 根组件文件名(不含扩展名),默认 App.root
})
参数说明类型默认值
rootFileName根组件文件名(不含 .vue 扩展名)string'App.root'

如需使用其他文件名(如 App.global.vue),修改配置即可:

ts
UniRoot({ rootFileName: 'App.global' })

工作原理

插件在 Vite 构建时完成三件事情:

  1. main.ts 注入:自动导入 App.root.vue 并注册为全局组件 global-root-view
  2. 页面模板包裹:解析每个页面的 SFC,在 <template> 内包裹 <global-root-view>
  3. Slot 渲染App.root.vue 中的 <slot /> 接收并渲染页面原始内容

整个过程是纯字符串操作,零额外依赖,不依赖任何平台特定 API,所有 UniApp 支持的平台均可正常工作。

跨端兼容

平台支持
H5
微信小程序
支付宝小程序
头条/抖音小程序
Android App
iOS App
鸿蒙 App

注意事项

  • Vue 版本需 >= 3.2.13(使用 vue/compiler-sfcparse API)
  • 页面模板中如有 <page-meta> 组件,会被自动提取到包裹层外部,确保微信小程序兼容
  • 页面模板中如有嵌套 <template #slot> 具名插槽,不影响根模板的正确识别
  • 修改 pages.json 后插件会自动重载页面列表,无需手动重启开发服务器

致谢

本插件的实现参考了 @uni-ku/root(MIT License,作者 skiyee),核心思路受其启发并进行了重新实现。

最后更新于: