借助 Vite 模拟出虚拟根组件(支持SFC的App.vue),解决 uniapp 无法使用公共组件问题
- 自定义虚拟根组件文件命名(App.ku.vue文件命名支持更换)
- 更高灵活度的获取虚拟根组件实例(获取KuRootView的Ref)
- 自动提取PageMeta到页面顶层(自动提升小程序PageMeta[用于阻止滚动穿透]组件)
📦 安装
pnpm add -D @uni-ku/root
yarn add -D @uni-ku/root
npm install -D @uni-ku/root
🚀 使用
1. 引入 @uni-ku/root
// vite.config.(js|ts)
import Uni from '@dcloudio/vite-plugin-uni'
import UniKuRoot from '@uni-ku/root'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
// 若存在改变 pages.json 的插件,请将 UniKuRoot 放置其后
UniKuRoot(),
Uni()
]
})
Note
CLI :
直接编写根目录下的 vite.config.(js|ts)HBuilderX :在根目录下
创建vite.config.(js|ts) 并写入
2. 创建 App.ku.vue(可自定义此根组件名称,请下拉至功能参考设置)
通过标签 <KuRootView /> 或 <ku-root-view /> 指定视图存放位置,并且可以将该标签放置到 template 内任意位置,但仅可有一个
<!-- src/App.ku.vue | App.ku.vue -->
<script setup lang="ts">
import { ref } from 'vue'
const helloKuRoot = ref('Hello AppKuVue')
</script>
<template>
<div>{{ helloKuRoot }}</div>
<!-- 顶级 KuRootView -->
<KuRootView />
<!-- 或内部 KuRootView,无论放置哪一个层级都被允许,但仅可有一个! -->
<div>
<KuRootView />
</div>
</template>
Note
CLI: 需要在 src目录 下创建下 App.ku.vue (或自定义名称)
HBuilderX: 直接在 根目录 下创建 App.ku.vue (或自定义名称)
Important
该标签与 VueRouter 中的 RouterView 功能类似,但请注意,由于Uniapp-Vue的局限性,该功能并不完全等同于VueRouter的 RouterView
功能
功能一:自定义虚拟根组件名称(默认:App.ku.vue)
- 通过设置 vite.config.(js|ts) 下插件的参数
rootFileName来自定义虚拟根组件名称
// vite.config.(js|ts)
import Uni from '@dcloudio/vite-plugin-uni'
import UniKuRoot from '@uni-ku/root'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
UniKuRoot({
// 默认含后缀 .vue,直接设置命名即可
rootFileName: 'KuRoot',
}),
// ...other plugins
]
})
- 创建/修改虚拟根组件为
KuRoot.vue,即可实现自定义,其余功能不变
// App.ku.vue 文件重命名为 KuRoot.vue
功能二:使用虚拟根组件实例(即:App.ku.vue)
有两种启用方式,局部或全部启用
一、 局部启用
-
暴露出 App.ku.vue 里所要被使用的变量或方法
<script setup lang="ts"> import { ref } from 'vue'const helloKuRoot = ref('Hello AppKuVue')
const exposeRef = ref('this is form app.Ku.vue')
defineExpose({
<template>
exposeRef,
})
</script></template>{{ helloKuRoot }}<KuRootView /> -
在 template 内编写 root="uniKuRoot",并通过 const uniKuRoot = ref() 获取模板引用
uniKuRoot 仅是一个变量,你可以根据你习惯重新命名
<!-- src/pages/*.vue -->
<script setup lang="ts">
import { ref } from 'vue'
const uniKuRoot = ref()
</script>
<template root="uniKuRoot">
<view>
Hello UniKuRoot
</view>
</template>
二、全局启用
-
通过配置
enabledGlobalRef开启全局自动注入 App.ku 实例// vite.config.(js|ts)
import Uni from '@dcloudio/vite-plugin-uni'
import UniKuRoot from '@uni-ku/root'
import { defineConfig } from 'vite'export default defineConfig({
plugins: [
UniKuRoot({
enabledGlobalRef: true
}),
Uni()
]
}) -
暴露出 App.ku 里所要被使用的变量或方法
<script setup lang="ts"> import { ref } from 'vue'const helloKuRoot = ref('Hello UniKuRoot')
const exposeRef = ref('this is from App.ku.vue')
defineExpose({
<template>
exposeRef,
})
</script></template>{{ helloKuRoot }}<KuRootView /> -
通过特有内置方法 getCurrentPages()= 获取暴露的数据
<script setup lang="ts"> import { onMounted, ref } from 'vue'const pagesStack = getCurrentPages()
const uniKuRoot = ref()onMounted(() => {
<template> <view> Hello UniKuRoot </view> </template>
uniKuRoot.value = pagesStack[pagesStack.length - 1].vm.refs.uniKuRoot
})
</script>
功能三:过滤掉不需要根组件的页面
如果遇到一些不需要根组件的页面,可以设置 excludePages 选项来过滤
excludePages选项支持采用 glob 模式进行编写
// vite.config.(js|ts)
import Uni from '@dcloudio/vite-plugin-uni'
import UniKuRoot from '@uni-ku/root'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
UniKuRoot({
excludePages: [
'pages/exclude.vue',
'pages/exclude/**/*.vue'
],
}),
Uni()
]
})
✨ 例子
以下例子均以 CLI 创建项目为例, HBuilderX 项目设置同理, 只要注意是否需要包含 src目录 即可
不仅是 Toast 组件,还可以是 Message、LoginPopup 等等
-
编写 Toast 组件
<script setup lang="ts"> import { useToast } from '@/composables/useToast'const { globalToastState, hideToast } = useToast()
<template>
</script></template> <style scoped> .toast-wrapper{ position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; }welcome to use @uni-ku/root.toast-box{
background: white;
color: black;
}
</style> -
实现 Toast 组合式API
// src/composables/useToast
import { ref } from 'vue'
const globalToastState = ref(false)
export function useToast() {
function showToast() {
globalToastState.value = true
}function hideToast() {
globalToastState.value = false
}return {
globalToastState,
showToast,
hideToast,
}
} -
挂载至 App.ku.vue
<script setup lang="ts"> import GlobalToast from '@/components/GlobalToast.vue' </script> <template> <KuRootView /> <GlobalToast /> </template> -
视图内部触发全局 Toast 组件
<script setup lang="ts"> import { useToast } from '@/composables/useToast'const { showToast } = useToast()
<template> <view> Hello UniKuRoot </view> <button @click="showToast"> 视图内触发展示Toast </button> </template>
</script>
与uni-helper-layouts的区别
root的核心理念就是尽可能的靠近Vue中的App.vue,layouts 则是类nuxt的布局系统
- root 是 layouts 之上,提供更多的自由度,能够实现layouts的效果,更加容易控制布局组件
- root 能够使用PageMeta,自动提取到页面顶层节点
- root 拥有不同的方式使用模板引用