乐于分享
好东西不私藏

AI 开发 App 从 0 到上架全过程· 第 07 篇:UniApp 项目骨架与目录约定

AI 开发 App 从 0 到上架全过程· 第 07 篇:UniApp 项目骨架与目录约定

App 端初始化:UniApp 项目骨架与目录约定

uni-preset-vue · pages.json · uview-plus easycom · 目录约定 · 路径别名 · CSS 兼容

后端 pig 跑起来后,App 端就可以并行推进了。这一篇记录我用 HBuilderX 创建 uni-preset-vue 项目、引入 uview-plus、定下目录约定的全过程。

重点不是「怎么装 HBuilderX」,而是几个关键决定:为什么选 uni-preset-vue 而不是 cli 脚手架pages.json 的「地图即路由」哲学uview-plus 的 easycom 自动按需引入目录约定config.js 的 baseUrl 切换

一、为什么是 UniApp + uni-preset-vue

1.1 选 UniApp 的原因

  • 一套代码三端跑:H5、小程序、App 全覆盖

  • Vue 3 语法:跟管理后台技术栈统一,不用切换思维

  • HBuilderX 真机调试丝滑:扫码即装,比 react-native 强太多

1.2 为什么选 uni-preset-vue 模板

UniApp 创建项目有两种方式:

方式
创建命令
特点
HBuilderX 可视化
文件 → 新建 → 项目 → uni-app
最快,自带模板,但配置不透明
cli 脚手架
vue create -p dcloudio/uni-preset-vue#vite
配置透明,可定制,但要懂 Vite

我选的是第二种 cli 方式,但用 HBuilderX 打开。原因:HBuilderX 可视化创建的项目用 webpack 构建,慢;cli 方式用 Vite,开发热更新快很多。但有个前提:cli 创建的项目必须用 HBuilderX 运行到手机/模拟器

1.3 前置条件

  • HBuilderX 4.x+(必须是 App 开发版,Alpha 版也行)

  • Node.js 20 LTS(跟 pig-ui 对齐,避免版本跳跃)

  • Android 模拟器或真机(用真机更靠谱,扫码调试省事)

二、创建项目

2.1 用 cli 创建 uni-preset-vue + vite 项目

为什么用 degit 而不是 vue create:degit 比直接 clone 快,不会带 git 历史。#vite-ts 是指定模板分支,表示「vite + TypeScript」版本。

2.2 项目结构预览

2.3 验证项目能跑

浏览器打开 http://localhost:5173,看到 UniApp 默认首页,说明项目骨架 OK。

小坑:第一次 npm run dev:h5 可能会报「vite-plugin-uni」找不到,再 npm install 一次就好。

三、pages.json:UniApp 的「地图即路由」哲学

3.1 什么是「地图即路由」

Vue Router 是「路由表 + 组件映射」的模式。UniApp 的 pages.json 不一样——它既是路由表,又是页面元信息载体。每个页面的导航栏样式、tabBar、标题、是否需要登录,全部写在 pages.json 里。这就是「地图即路由」:pages.json 就是整个 App 的地图,看一眼就知道有多少页面、每个页面长什么样。

3.2 pages.json 的核心结构

3.3 三个关键概念

① pages 数组的第一项是启动页

pages 数组的第一个元素,就是 App 启动后默认打开的页面。我的做法是:首页(index)放第一个,登录判断在首页里做。这样启动快,不会被登录页阻塞。

② globalStyle 是全局默认样式

所有页面共享的导航栏样式、背景色,写在 globalStyle 里。单个页面要覆盖时,在 pages 数组对应项的 style 里改。

③ tabBar 最多 5 个

tabBar 是底部导航栏,最少 2 个、最多 5 个。我用了 2 个:笔记、我的。每个 tab 的 pagePath 必须在 pages 数组里存在。

3.4 我的 pages.json 配置策略

注意:tabBar 里的 pagePath 必须出现在 pages 数组里,但不一定排在前面。tabBar 页面会被预加载,跳转速度快。

四、引入 uview-plus:easycom 自动按需引入的魔法

4.1 uview-plus 是什么

uview-plus 是 uni-app 生态里最全的 Vue3 组件库,提供按钮、表单、列表、弹窗等 80+ 组件,跨端兼容。

4.2 安装

npm install uview-plus

4.3 配置 easycom(核心)

UniApp 的 easycom 机制是:只要你装了 uview-plus,在 template 里直接写 <u-button> 就能用,不需要 import。但这需要在 pages.json 里配置:

这三条正则的含义:

  • ^u--(.*) → 匹配 <u--xxx>,某些特殊组件

  • ^up-(.*) → 匹配 <up-xxx>,另一种命名风格

  • ^u-([^-].*) → 匹配 <u-xxx>(注意 - 后面不能是 -),最常见的用法

配置完后,所有 u- 开头的组件都会被自动 import,按需打包,不会因为没用而增加包体积。

4.4 引入样式和工具函数

在 src/main.ts 里加:

在 src/App.vue 里加全局样式:

在 src/uni.scss 里引入 uview-plus 主题变量:

4.5 验证 easycom 生效

跑起来看到紫色按钮,说明 easycom 生效。

4.6 easycom 的坑

坑一:组件没生效,控制台报「Failed to resolve component」

99% 是 pages.json 的 easycom 配置没生效。检查点:easycom 必须在 pages.json 的最外层(跟 pages 同级),不能写在 pages 数组里;正则写错。

坑二:H5 能跑,App 端报错

某些 uview-plus 组件依赖 H5 环境,App 端不支持。例如 <u-parse> 的某些高级用法。写跨端代码时一定看官方文档的「平台差异说明」

坑三:easycom 配置后 npm install 重装,组件全失效

这是缓存问题。解决:停止 dev server → 删除 node_modules → npm install → 重启。

五、目录约定:可扩展的 App 端结构

5.1 我推荐的目录结构

5.2 几个关键约定

① pages 目录按业务模块组织

不要把所有页面平铺在 pages 下。用 pages/note/detail/index.vuepages/note/edit/index.vue 这种「模块/子页面/index.vue」结构,扩展性强。

② api 目录按业务模块拆分

每个业务模块一个 api 文件:api/user.tsapi/note.ts。接口多了再拆 api/note/detail.tsapi/note/edit.ts

③ components 只放全局组件

只在某一个页面用到的组件,放页面目录下:pages/index/components/xxx.vue。components 只放跨页面复用的。

④ composables 用 use 前缀

Vue 3 组合式函数约定用 use 开头:useAuthuseNote。看到名字就知道是 hook。

六、config.js:环境配置

6.1 为什么需要 config.js

开发时连本地后端 http://192.168.1.100:9999,生产时连线上 https://api.brainypipe.com。不能在代码里写死,必须用配置文件统一管理。

6.2 创建 src/config/index.ts

6.3 关键点解释

① import.meta.env.PROD

这是 Vite 内置的环境变量,生产环境(npm run build:xxx)返回 true,开发环境(npm run dev:xxx)返回 false。不需要自己配置 .env 文件。

② 为什么不用 process.env.NODE_ENV

Vite 不暴露 process.env,用 import.meta.env 是 Vite 的标准。

③ 怎么加自定义环境变量

在项目根目录创建 .env.env.development.env.production,里面用 VITE_XXX 开头的变量,代码里用 import.meta.env.VITE_XXX 读。但我这种小项目,直接判断 PROD 够用了。

七、路径别名配置:告别 ../../../

7.1 为什么要配路径别名

项目大了之后,深层目录的文件 import 时会出现 ../../../api/user 这种相对路径,难读、改路径就崩。配了别名后变成 @/api/user,清爽。

7.2 配置 vite.config.ts

说明@ 和 /@ 都指向 src,前者用于 JS import,后者用于 template 里的静态资源引用。

7.3 配置 tsconfig.json(让 TS 识别别名)

配完后,IDE 才不会报错,跳转也能用。

八、CSS 兼容性踩坑与全局样式约定

8.1 不用 gap 属性

CSS gap 在 H5 现代浏览器支持很好,但 Android 4.x WebView 不支持。App 端某些低版本 WebView 跑 flex + gap 会无效。统一用 margin 替代:

8.2 全部用 rpx 单位

rpx 是 UniApp 的响应式像素,设计稿 750px 宽度下 1rpx = 1px。在 H5、小程序、App 三端都能自动适配。固定像素用 px,需要响应式用 rpx。

8.3 在 uni.scss 定义全局变量

在 .vue 文件里 @import '@/uni.scss' 后就能用这些变量。

九、ZPaging:列表渲染神器

9.1 为什么不用 scroll-view

UniApp 自带的 scroll-view 在数据量大时性能差,长列表会卡顿。ZPaging 是 uni-app 生态里性能最好的分页列表组件,支持虚拟列表、下拉刷新、上拉加载。

9.2 安装

npm install z-paging

9.3 在 pages.json 注册 easycom

9.4 基础用法

ZPaging 会自动管理分页、下拉刷新、上拉加载、空数据展示,你只需要把请求到的数据 complete 给它。

9.5 ZPaging 使用规范

禁止事项

  • 不要在 z-paging 外层再套 scroll-view

  • 不要在 z-paging 内部用 v-if 大量切换 DOM

  • 不要在 queryList 回调里同步赋值 dataList(z-paging 自己管)

推荐做法

  • 每个列表页用一个独立的 z-paging 实例

  • 列表项用 :key 绑定唯一 id(不要用 index)

  • 空数据自定义 #empty 插槽

十、真机调试:从「能跑」到「真跑」

10.1 为什么要真机调试

H5 跑得通不代表 App 端跑得通。真机上会暴露三类问题:WebView 兼容性(CSS、JS API)、原生组件差异(input、video)、网络/权限(HTTPS、存储)。

10.2 真机调试步骤

  1. HBuilderX 打开项目 → 菜单「运行」→「运行到手机或模拟器」→「运行到 Android App 基座」

  2. 手机和电脑同一 Wi-Fi → HBuilderX 自动检测到设备 → 点「运行」

  3. 手机自动安装「HBuilder 标准基座」 → 启动 App

  4. 修改代码 → 保存 → 自动热更新到手机

常见问题:手机检测不到 → 检查手机是否开启「USB 调试」和「允许 ADB 调试」。小米/红米要额外开「USB 调试(安全设置)」。

10.3 连接本地后端

真机访问电脑 IP,要保证两点:

  1. 手机和电脑同一 Wi-Fi(不是插 USB 就能联网)

  2. 电脑防火墙放行 9999 端口(pig 后端端口)

在 config/index.ts 里把 baseUrl 改成电脑内网 IP:http://192.168.1.100:9999localhost 在手机里指手机自己)。

十一、踩坑总结

11.1 HBuilderX 版本必须对齐

cli 创建的项目用的 uni-app 依赖版本,必须和 HBuilderX 版本一致。否则真机运行会报「uni-app 编译器版本和运行时版本不一致」。解决:package.json 里的 @dcloudio/* 全部指定为 HBuilderX 对应版本号。

11.2 easycom 配置顺序

easycom 必须在 pages.json 的最外层,且写在 pages 之前。配置后必须重启 dev server,热更新不生效。

11.3 TypeScript 严格模式

uni-preset-vue vite-ts 模板默认开了 TS 严格模式,any 会报警告。建议前期保持严格,定义好接口类型,后期维护轻松。真嫌烦可以 tsconfig.json 里把 strict: false

11.4 安卓打包体积

第一次云打包安卓 apk 出来 30+ MB,正常现象(含 uni-app 运行时 + V8 引擎)。要瘦身:用「自有证书」打包、按需配置 manifest.json 的模块(不要全选)。

十二、写在最后

这一篇把 App 端的项目骨架搭起来,配置好 uview-plus、ZPaging、路径别名、环境配置,目录约定也定下来了。这套结构能撑住至少到 v1.0 发布,业务增长再按需拆分。

回顾一下这一篇的关键决定:

  • uni-preset-vue vite-ts:Vite + TS,开发体验最好

  • uview-plus easycom:写组件名即用,按需打包

  • pages.json 是地图:路由 + 元信息一体

  • config/index.ts:用 import.meta.env.PROD 切换 baseUrl

  • ZPaging:长列表用 ZPaging,别用 scroll-view

  • rpx + margin:不用 gap,跨端兼容

下一篇开始写第一个页面:登录页。涉及 uview-plus 表单组件、表单校验、token 存取、跳转逻辑。

「挑战用 AI 开发 App 从 0 到上架全过程」系列 · 第 07 篇 · App 端初始化