# Jun-uni
**Repository Path**: ljb2458/jun-uni
## Basic Information
- **Project Name**: Jun-uni
- **Description**: 一个使用 Uniapp + Vue3 + TypeScript + uv-ui | wd-ui + Vite 打造的开箱即用框架,封装了CoRequsetList CoTabsFor 等特色组件,所有组件均拥有良好的 TypeScript 类型支持
- **Primary Language**: TypeScript
- **License**: MIT
- **Default Branch**: master
- **Homepage**: https://gitee.com/ljb2458/jun-uni
- **GVP Project**: No
## Statistics
- **Stars**: 12
- **Forks**: 1
- **Created**: 2023-07-03
- **Last Updated**: 2025-09-25
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
#
Jun-uni
## 项目介绍
> ⭐`Jun-uni` 是一个由个人开发者 `Juncoder` 积累四年开发经验打造的适用中小型公司一般开发情况的 uniapp 开箱即用高效开发框架。
> ⭐`Jun-uni` 的诞生是为了解决 `Uniapp` 多端兼容麻烦、使用 `HBuilder X` 开发体验一般、对 `TypeScript` 支持不好的问题,旨在优化开发体验、减少兼容代码。
> ⭐ 该框架使用 `Uniapp` `Vue3` `TypeScript` `Pinia` `luchRequest` `Vite` `uv-view` 打造。
> 因此在使用此框架前,我推荐你先学习或了解 `Uniapp` `Vue3` `TypeScript` `Pinia` `Axios(luchRequest)`
> 该框架使用的 `node` 版本为 `v22.13.1` 为了减少运行时所带来的错误,请尽可能使用与 `v22.13.1` 相近的版本。
### 框架解决了以下开发痛点
- ⭐`pages.json` 配置麻烦、不便查阅?
- 使用 `vite` 插件 `generatePagesJson` 自动生成 `pages.json` 配置文件。
- 配置项直接写在当前 `vue` 文件中,一目了然。
- 文件目录就是小程序分包方式,非常好理解。
- ⭐ 习惯 `vs code` 开发,可在 vs code 中 `uniapp` 原生组件总是没代码提示?
- 每个 uniapp 原生组件都有类型标注,无需担心代码提示问题。
- ⭐ 实现 `tabs` 选项卡,高度总是问题?
- 使用组件 `CoTabsFor` 传入一个数组,定义一个插槽可以轻松实现自动高度的 tabs 选项卡。
- ⭐ 分页列表处理麻烦,总是涉及数组操作?
- 使用组件 `CoRequestList` ,仅需传入一个使用适配器包装后的 `api` 方法 加上一个 `item` 插槽,即可加载分页数据。
- ⭐ 自定义导航栏注册麻烦,担心与原生导航栏冲突,计算页面高度时还需要考虑有没有开启自定义导航?
- 在组件 `CoPageView` 中根据 `pages.json` 对应配置,**自动决定要不要注册自定义导航栏**。
- 在组件 `CoPageView` 为您计算好导航栏高度和页面可用高度,生成 css 样式 `--layout-navbar-height` 和 `--layout-page-height`。
- ⭐ 写在底部的固定按钮,忘记计算底部安全区、忘记写占位符,导致页面最底部元素被按钮遮盖,无法完整的查看?
- 在组件 `CoPageView` 中提供了 `fixedBottom` 插槽,计算安全区并在页面生成占位元素的同时,将你的元素定位到页面最底部。
- ⭐`uni.request` 不够好用?
- `/utils/httpRequest` 基于 `luchRequest` 进行二次封装,神似 `Axios` 有请求拦截器、响应拦截器、自动提示等。
- ⭐ 路由跳转、路由传参需要自己拼接字符串?
- `/utils/router` 二次封装路由跳转,自动拼接 `Query` 参数。
- ⭐ 找不到对 `TypeScript` 支持良好的 `uniapp` 框架?
- `Jun-uni` 框架中的所有 方法、组件、示例代码、包括 `uniapp` 的原生组件,均有良好的 `TypeScript` 支持
- ⭐ 微信小程序组件总是多渲染一层组件盒,影响样式编写?
- 每个公共组件都不会有多余的组件盒,减少平台差异。
- `Jun-uni` 框架中的所有 方法、组件、示例代码、包括 `uniapp` 的原生组件,均有良好的 `TypeScript` 支持
- 开启了过多相同的循环定时器,造成性能浪费、忘记关闭循环定时器?
- 使用 `/hooks/toolsHooks` 中的 `useInterval` 同样间隔时间的循环定时器只会被开启一次。
- 全局状态管理 `store(pinia、vuex)` 数据持久化麻烦?
- `pinia + mp-storage + pinia-plugin-persistedstate` 简单而优雅的解决问题。
- `picker` 用户体验不好,市面上又缺少好用的级联选择器?
- `CoCascader 级联选择器组件` 动画流畅,使用简单。
- 分栏编写样式麻烦、样式名难想、`tailwindcss` 体积太大、不好定制、且对小程序支持不好?
- 支持 `unocss` + `unocss-preset-uni` 来支持小程序,使用官方插件获得代码提示。
- 主题不好定制,定制好自己的颜色还要定制 UI 框架的颜色?
- src/constants/unocss 专门的配置文件,一键配置你的项目主题。
## 预览
| 微信小程序请扫这里 | App 请点击这里下载 |
| ------------------------------------------------------------ | ----------------------------- |
|
| [安卓下载链接](./README/apk/) |
## 开始
### 拉取
```bash
git clone https://gitee.com/ljb2458/jun-uni.git
```
- 使用 `VS code` 打开项目。
- 接受弹出的推荐插件。
- 如果你需要我的更新,推荐**新建分支**进行开发,并定期**合并代码**。
### 首次启动
- 安装依赖
```shell
pnpm i
```
- 启动
```shell
//网页
pnpm run dev:h5
//微信小程序
pnpm run dev:mp-weixin
```
- 然后根据控制台提示进行操作。
- 或在 `HBuilder X` 中启动项目。
## 习惯与环境
**使用该框架,我推荐你使用 `vs code` 编译器并接受安装我为你推荐的 vscode 插件** —— 在首次进入项目时编译器会提示你安装我所推荐的插件。你也可以在 .vscode/extensions.json 以此复制 recommendations 的每一项搜索并安装。
**使用该框架,我推荐你添加以下代码片段。**
`vs code` 左下角小齿轮=>代码片段=>选择 `vue3-module.code-snippets`
```json
{
//其他代码片段...
"uniapp页面": {
"prefix": "uni-page",
"body": [
"",
"{",
" \"navigationBarTitleText\": \"${1:新页面}\",",
" \"enablePullDownRefresh\": false,",
" \"navigationStyle\": \"custom\",",
" \"navigationBarTextStyle\": \"white\"",
"}",
"",
"",
"",
"",
"",
" ",
"$3",
" ",
"",
"",
"",
""
],
"description": "uniapp 页面"
}
}
```
`vs code` 左下角小齿轮=>代码片段=>选择 `typescript.json`
```json
{
//其他代码片段...
"pinia仓库": {
"prefix": "pinia-store",
"body": [
"import { defineStore } from \"pinia\";",
"//import { localStorage } from \"mp-storage\";",
"",
"export const use$1Store = defineStore(\"$1Store\", {",
" //*全局仓库",
" state,",
" //*全局函数",
" actions: {},",
" //*计算属性",
" getters: {},",
" //*仓库数据缓存",
" persist: [",
" {",
" key: \"$1Store\",",
" storage: localStorage, //指定储存位置",
" },",
" ],",
"});",
"/**state类型定义 */",
"export namespace $1Store {",
" export interface Store {}",
"}",
"/**初始化pinia */",
"function state(): $1Store.Store {",
" return {",
" };",
"}",
""
],
"description": "pinia仓库"
},
"api接口模板": {
"prefix": "api-template",
"body": [
"/**${3:模板接口} */",
"export async function api${2:Template}(",
" data: Api${2:Template}.Req",
"): Promise> {",
" const res = await defHttp.post>(\"${1:记得替换我}\", data, {",
" custom: {",
" failMessage: true,",
" },",
" });",
" return res;",
"}",
"",
"/**${3:模板接口} */",
"export namespace Api${2:Template} {",
" export interface Req {}",
" export interface Res {}",
"}",
""
],
"description": "api接口模板"
}
}
```
使用这个代码模板可以快速生成改框架常用的代码块。
## 文件目录
```
vite-plugins | //存放本地 vite 插件。
|-generatePagesJson |-index.ts //用于生成pages.json配置文件;
src |-layout | //存放在 CoPageView 中注册的组件,一般会在全部页面使用。
|-style | //存放预设、公共、scss 文件。
|-components|-common //存放公用组件,一般为自创组件。
|-group //存放组合组件,一般为多个组件的纯粹组合,非新组件。
|-rewrite //存放二次封装的组件,一般改动较小,基本保持原组件的概念。
|-native //存放一般只有这个项目才能用到的公共业务组件。
|-constants | //存放一些常量,包括发布订阅所用的Key等。
|-init.ts //项目加载、App.vue 初始化、登录完成 时干的事。
types |-dts | //全局配置、组件、等ts存放目录
|-modult.d.ts //全局模块声明
|-typeFunction.d.ts //自定义ts类型生成与转换方法
|-components.d.ts //全局组件ts声明目录
|-auto-import | //自动生成ts类型存放目录
```
## 对接后端接口
1. 设置接口地址及后缀
1. 在 `/.env.development、/.env.production` 中修改 `VITE_API_URL 接口请求地址`,**⚠ 注 ❗ 如果为空请将该行注释。没有值的 `env` 配置文件 将会造成 `h5` 无法正常启动的诡异问题**
```env
# 请求接口地址
VITE_API_URL=https://你的api接口地址
# 其它配置...
```
2. 重启项目。
2. 修改示例 `token` 的传递方式
1. 在 `/src/api/index.ts` 中找到 `defHttp.interceptors.request.use` 修改其中的请求配置。
```ts
//请求拦截器,在这里设置 token
defHttp.interceptors.request.use((config) => {
const userStore = useUserStore();
config.header = {
...config.header,
token: userStore.token,
};
return config;
});
```
3. 修改返回结果的类型
1. 在 `/src/api/index.ts` 中找到 `export namespace Api` 修改其中的类型定义。
```ts
/**请求res类型 */
export namespace Api {
export interface SuccessRes {
code: 200;
message: string;
time: Date;
type: string;
isSuccess: true;
result: T;
}
export interface FailRes {
code: number;
message: string;
time: Date;
type: string;
isSuccess: false;
result?: T;
}
export type Res = SuccessRes | FailRes;
}
```
4. 修改示例 `isSuccess`、`giveMsg`、`giveErrMsg` 方法
1. 在 `/src/api/index.ts` 中找到 `export const defHttp = createHttpRequest` 方法,修改传入的两个个函数为实际数据。
```ts
export const defHttp = createHttpRequest(
{
isSuccess(res) {
return res?.data?.code === 200;
},
giveMsg(res) {
return res?.data?.message;
},
giveErrMsg(error) {
return error?.errMsg;
},
},
{
baseURL,
}
);
```
5. 在 `/src/api/userinfo` 中复制粘贴或直接修改一个接口并调用。
## 路由鉴权
在 src/init.ts 中有一个 routerCheck 方法,在这里编写路由鉴权的逻辑。让后在 .env.development 中将 VITE_REQUIRED_LOGIN 设为 1
## 自动生成 pages.json(vite 插件)
在 `vite.config.ts` 中需改 `generatePagesJson` 中的相关配置
```ts
//其它代码...
generatePagesJson({
/**输出文件 */
outFile: "./src/pages.json",
/**第一个页面 */
firstPage: "./src/pages/tabbar/home/home.vue",
/**主包文件夹 */
mainPackageDir: "./src/pages/tabbar/",
/**页面所在目录 */
pagesDir: "./src/pages/",
}),
```
### 页面生成规则
- `generatePagesJson` 会自动将 `/src/pages` 下的每一个目录当作一个分包生成,而`mainPackageDir` 所指向的文件夹将会被放到主包配置内。
- `generatePagesJson` 插件会读取 `pages.json` 下的配置对象,并替换 `pages` 和 `subPackages` 这两项配置,你可以放心的修改除这两项配置以外的配置。
## 选型解释
- 为什么不使用 `vite-plugin-uni-pages` 来实现自动生成 `pages.json`?
- `vite-plugin-uni-pages` 从大体上确实能实现该功能,但 `vite-plugin-uni-pages` 不符合规范大于配置的设计理念,在使用了 `vite-plugin-uni-pages` 后,任需要手动配置分包规则,因此,作者自己写了一个本地 `vite` 插件。
## 旧版本
该框架已经从自写 `原子化 css` 迁移至 `unocss` 不再建议使用自写 `原子化 css` 进行开发,旧版本的,可以在 src/styles/index.scss 与同路径下的 effects.scss 中解开相应注释继续使用。
该框架已转到 `wot-design-uni` 框架,并打算以后将 `wot-design-uni` 作为主力框架,建议使用 `wot-design-uni` 作为 UI 框架进行开发,已有的组件会进行兼容。