Skip to content
/ root Public
generated from skiyee/quick-template

🦾 解决 Uniapp 无法使用公共组件问题

License

Notifications You must be signed in to change notification settings

uni-ku/root

Repository files navigation

Root

借助 Vite 模拟出虚拟根组件(支持SFC的App.vue),解决 uniapp 无法使用公共组件问题

NPM version NPM downloads LICENSE

Tip

从 v0.2.0 开始, 已支持 HBuilderX 创建的 Vue3 项目

🎏 支持

  • Uniapp-CLI 或 HBuilderX 创建的 Vue3 项目
  • 自定义虚拟根组件文件命名
  • 更高灵活度的获取虚拟根组件实例

📦 安装

pnpm add -D @uni-ku/root

yarn add -D @uni-ku/root

npm install -D @uni-ku/root

🚀 使用

1. 引入 @uni-ku/root

Note

CLI直接编写 根目录下的 vite.config.(js|ts)

HBuilderX:在根目录下 创建 vite.config.(js|ts) 并写入

// vite.config.(js|ts)

import { defineConfig } from 'vite'
import UniKuRoot from '@uni-ku/root'
import Uni from '@dcloudio/vite-plugin-uni'

export default defineConfig({
  plugins: [
    // 若存在改变 pages.json 的插件,请将 UniKuRoot 放置其后
    UniKuRoot(),
    Uni()
  ]
})

2. 创建 App.ku.vue(可自定义此根组件名称,请下拉至功能参考设置)

Note

CLI: 需要在 src目录 下创建下 App.ku.vue (或自定义名称)

HBuilderX: 直接在 根目录 下创建 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>

Important

该标签与 VueRouter 中的 RouterView 功能类似,但请注意,由于Uniapp-Vue的局限性,该功能并不完全等同于VueRouter的 RouterView

🎉 功能

(点击展开) 功能一:自定义虚拟根组件名称(默认:App.ku.vue)

1. 通过设置 vite.config.(js|ts) 下插件的参数 rootFileName 来自定义虚拟根组件名称

// vite.config.(js|ts)

import { defineConfig } from 'vite'
import UniKuRoot from '@uni-ku/root'
import Uni from '@dcloudio/vite-plugin-uni'

export default defineConfig({
  plugins: [
    UniKuRoot({
      // 默认含后缀 .vue,直接设置命名即可
      rootFileName: 'KuRoot',
    }),
    // ...other plugins
  ]
})
  1. 创建/修改虚拟根组件为 KuRoot.vue,即可实现自定义,其余功能不变
(点击展开) 功能二:使用虚拟根组件实例(即:App.ku.vue)

[!TIP] 有两种启用方式,局部或全部启用

一、 局部启用

1. 暴露出 App.ku.vue 里所要被使用的变量或方法

<!-- src/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({
  exposeRef,
})
</script>

<template>
  <div>
    <div>{{ helloKuRoot }}</div>
    <KuRootView />
  </div>
</template>

2. 在 template 内编写 root="uniKuRoot",并通过 const uniKuRoot = ref() 获取模板引用

[!TIP] uniKuRoot 是同一个变量,你可以根据你命名相关命名

<!-- src/pages/*.vue -->

<script setup lang="ts">
import { ref } from 'vue'

const uniKuRoot = ref()
</script>

<template root="uniKuRoot">
  <view>
    Hello UniKuRoot
  </view>
</template>

二、全局启用

1. 通过配置 enabledGlobalRef 开启全局自动注入 App.ku 实例

// vite.config.(js|ts)

import { defineConfig } from 'vite'
import UniKuRoot from '@uni-ku/root'
import Uni from '@dcloudio/vite-plugin-uni'

export default defineConfig({
  plugins: [
    UniKuRoot({
      enabledGlobalRef: true
    }),
    Uni()
  ]
})

2. 暴露出 App.ku 里所要被使用的变量或方法

<!-- src/App.ku.vue | App.ku.vue -->

<script setup lang="ts">
import { ref } from 'vue'

const helloKuRoot = ref('Hello UniKuRoot')

const exposeRef = ref('this is from App.ku.vue')

defineExpose({
  exposeRef,
})
</script>

<template>
  <div>
    <div>{{ helloKuRoot }}</div>
    <KuRootView />
  </div>
</template>

3. 通过特有内置方法 getCurrentPages() 获取暴露的数据

<!-- src/pages/*.vue -->

<script setup lang="ts">
import { onMounted, ref } from 'vue'

const pagesStack = getCurrentPages()
const uniKuRoot = ref()

onMounted(() => {
  uniKuRoot.value = pagesStack[pagesStack.length - 1].$vm.$refs.uniKuRoot
})
</script>

<template>
  <view>
    Hello UniKuRoot
  </view>
</template>

✨ 例子

Tip

以下例子均以 CLI 创建项目为例, HBuilderX 项目设置同理, 只要注意是否需要包含 src目录 即可

(点击展开) 示例一:全局共享组件例子:Toast

不仅是 Toast 组件,还可以是 Message、LoginPopup 等等

  1. 编写 Toast 组件
<!-- src/components/GlobalToast.vue -->

<script setup lang="ts">
import { useToast } from '@/composables/useToast'

const { globalToastState, hideToast } = useToast()
</script>

<template>
  <div v-if="globalToastState" class="toast-wrapper" @click="hideToast">
    <div class="toast-box">
      welcome to use @uni-ku/root
    </div>
  </div>
</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;
}

.toast-box{
  background: white;
  color: black;
}
</style>
  1. 实现 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,
  }
}
  1. 挂载至 App.ku.vue
<!-- src/App.ku.vue -->

<script setup lang="ts">
import GlobalToast from '@/components/GlobalToast.vue'
</script>

<template>
  <KuRootView />
  <GlobalToast />
</template>
  1. 视图内部触发全局 Toast 组件
<!-- src/pages/*.vue -->

<script setup lang="ts">
import { useToast } from '@/composables/useToast'

const { showToast } = useToast()
</script>

<template>
  <view>
    Hello UniKuRoot
  </view>
  <button @click="showToast">
    视图内触发展示Toast
  </button>
</template>
(点击展开) 示例二:全局共享布局例子:ConfigProvider

不仅仅只有ConfigProvider,还能是Layout、NavBar、TabBar等等!

  1. 以 Wot 组件库中 WdConfigProvider 为例子,了解更多Wot点这里
<!-- src/App.ku.vue -->

<script setup lang="ts">
import { useTheme } from './composables/useTheme'

const { theme, themeVars } = useTheme({
  buttonPrimaryBgColor: '#07c160',
  buttonPrimaryColor: '#07c160'
})
</script>

<template>
  <div>Hello AppKuVue</div>
  <!-- 假设已注册 WdConfigProvider 组件 -->
  <WdConfigProvider :theme="theme" :theme-vars="themeVars">
    <KuRootView />
  </WdConfigProvider>
</template>
  1. 编写主题相关组合式API
// src/composables/useTheme.ts

import type { ConfigProviderThemeVars } from 'wot-design-uni'
import { ref } from 'vue'

const theme = ref<'light' | 'dark'>(false)
const themeVars = ref<ConfigProviderThemeVars>()

export function useTheme(vars?: ConfigProviderThemeVars) {
  vars && (themeVars.value = vars)

  function toggleTheme(mode?: 'light' | 'dark') {
    theme.value = mode || (theme.value === 'light' ? 'dark' : 'light')
  }

  return {
    theme,
    themeVars,
    toggleTheme,
  }
}
  1. 切换主题模式
<!-- src/pages/*.vue -->

<script setup lang="ts">
import { useTheme } from '@/composables/useTheme'

const { theme, toggleTheme } = useTheme()
</script>

<template>
  <button @click="toggleTheme">
    切换主题,当前模式:{{ theme }}
  </button>
</template>

📝 待办

  • 支持热更新
  • 支持VueSFC
  • 支持小程序PageMeta
  • 支持 App.ku.vue 内直接编写控制逻辑
  • 补全单元测试

💬 社区

🏝 周边

项目 描述
Wot Design Uni 一个基于Vue3+TS开发的uni-app组件库,提供70+高质量组件
Create Uni 一个用于快速创建 uni-app 项目的轻量脚手架工具

💖 赞赏

如果我的工作帮助到了您,可以请我吃辣条,使我能量满满 ⚡

请留下您的Github用户名,感谢 ❤

微信赞赏

wechat-pay

赞赏榜单

sponsors