虚拟根组件
说明
本文档适用于 uView Pro 0.6.12 及以上版本,内置了虚拟根组件能力,无需额外安装第三方插件。
解决的问题
UniApp 不支持原生的根组件包裹机制,导致无法在全局统一注入 u-config-provider、u-toast、u-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-provider 和 useTheme,实现全局主题切换:
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 构建时完成三件事情:
- main.ts 注入:自动导入
App.root.vue并注册为全局组件global-root-view - 页面模板包裹:解析每个页面的 SFC,在
<template>内包裹<global-root-view> - Slot 渲染:
App.root.vue中的<slot />接收并渲染页面原始内容
整个过程是纯字符串操作,零额外依赖,不依赖任何平台特定 API,所有 UniApp 支持的平台均可正常工作。
跨端兼容
| 平台 | 支持 |
|---|---|
| H5 | ✅ |
| 微信小程序 | ✅ |
| 支付宝小程序 | ✅ |
| 头条/抖音小程序 | ✅ |
| Android App | ✅ |
| iOS App | ✅ |
| 鸿蒙 App | ✅ |
注意事项
- Vue 版本需 >= 3.2.13(使用
vue/compiler-sfc的parseAPI) - 页面模板中如有
<page-meta>组件,会被自动提取到包裹层外部,确保微信小程序兼容 - 页面模板中如有嵌套
<template #slot>具名插槽,不影响根模板的正确识别 - 修改
pages.json后插件会自动重载页面列表,无需手动重启开发服务器
致谢
本插件的实现参考了 @uni-ku/root(MIT License,作者 skiyee),核心思路受其启发并进行了重新实现。
