Vue3 玩得溜,一上手 UniApp 就懵?生命周期分不清、页面传参摸不透、axios 用不了、Pinia 不知道怎么配、本地存储总踩坑……
如果你是Vue3+TS 开发者,想快速搞定 UniApp 跨平台开发,这篇实战指南帮你一次性扫清所有障碍,从环境搭建到完整商城 Demo,直接抄作业就能用!
一、🔥 快速上手:TS 版 UniApp 项目搭建
1.1 一键创建项目
命令行快速初始化 Vue3+Vite+TS 项目:
npx degit dcloudio/uni-preset-vue#vite-ts my-ts-app
cd my-ts-app
npm install
HBuilderX 用户:新建项目选择uni-app (Vue3) ,直接勾选启用 TypeScript即可。
1.2 TS 配置核心(tsconfig.json)
{
"compilerOptions": {
"types": ["@dcloudio/types", "miniprogram-api-typings"],
"strict": true,
"moduleResolution": "node",
"resolveJsonModule": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"]
}
1.3 类型声明补全(shims-uni.d.ts)
解决 Vue 文件 TS 报错问题:
declaremodule '*.vue' {
importtype { DefineComponent } from'vue'
const component: DefineComponent<{}, {}, any>
exportdefault component
}
二、⏰ 生命周期:一张表理清 Vue3 vs UniApp
很多人最懵的就是生命周期,直接看对比表,一秒看懂差异👇
✅ 组合式 API 代码示例
<scriptsetuplang="ts">
import { onMounted, ref } from'vue'
import { onLoad, onShow, onReady, onHide, onUnload } from'@dcloudio/uni-app'
const id = ref('')
// 只执行一次,接收参数
onLoad((options: any) => {
id.value = options.id
})
// 每次进入页面触发
onShow(() => {})
// DOM渲染完成,可获取元素位置
onReady(() => {})
// 页面隐藏
onHide(() => {})
// 页面卸载,清理定时器/监听
onUnload(() => {})
</script>
⚠️ 致命坑点
❌ onLoad 中绝对不能获取 DOM,此时页面未渲染 ❌ 页面卸载必须清理定时器、事件监听,否则内存泄漏
三、🚀 页面路由 & 传参:告别 Vue Router 思维
UniApp 没有$router/$route,全套用uni API,3 种传参方式直接用👇
3.1 URL 传参(最常用)
发送页:特殊字符必须编码
const name = encodeURIComponent('张三&李四')
uni.navigateTo({
url: `/pages/detail/detail?id=123&name=${name}`
})
接收页:onLoad 自动解码
onLoad((options: { id: string; name: string }) => {
// 直接获取,无需手动解码
console.log(options.id, options.name)
})
3.2 事件总线(跨页面通信)
发送页:
uni.$emit('updateCart', { count: 5 })
uni.navigateBack()
接收页:必须成对监听 & 移除
const handleUpdate = (data: { count: number }) => {}
onLoad(() => {
uni.$on('updateCart', handleUpdate)
})
onUnload(() => {
uni.$off('updateCart', handleUpdate) // 必写!
})
3.3 与 Vue Router 核心差异
无 $router:跳转用uni.navigateTo/redirectTo/switchTab无 $route:参数全靠onLoad(options)无嵌套路由:页面全扁平化,配置 pages.json
四、🌐 网络请求:抛弃 axios,封装 uni.request+TS
UniApp 不支持 axios(依赖 XHR),uni.request才是正统,封装成 Promise+TS 更优雅👇
4.1 通用请求封装(utils/request.ts)
interface RequestOptions {
url: string
method?: 'GET'|'POST'|'PUT'|'DELETE'
data?: any
header?: any
showLoading?: boolean
}
exportfunctionrequest<T = any>(options: RequestOptions): Promise<T> {
returnnewPromise((resolve, reject) => {
options.showLoading && uni.showLoading({ title: '加载中...' })
uni.request({
...options,
success: (res) => {
res.statusCode === 200 ? resolve(res.data as T) : reject(res)
},
complete: () => {
uni.hideLoading()
}
})
})
}
4.2 类型安全 API 调用
// api/user.ts
interface User { id: number; name: string }
exportconst getUserInfo = (id: number) => {
return request<User>({ url: `/user/${id}` })
}
// 页面使用
const user = await getUserInfo(123)
// TS自动推断类型,智能提示拉满
console.log(user.name)
五、💾 本地存储:别再用 localStorage!
UniApp 有专属存储 API,自动序列化对象,比 localStorage 强太多👇
✅ 代码示例
// 存对象(无需JSON.stringify)
uni.setStorageSync('user', { name: '张三', age: 18 })
// 取对象(无需JSON.parse)
const user = uni.getStorageSync('user') as { name: string; age: number } | null
// 删/清空
uni.removeStorageSync('user')
uni.clearStorageSync()
六、🧩 状态管理:Pinia 完美适配 UniApp
Pinia 轻量易用,完全兼容 UniApp,只需自己做持久化👇
6.1 安装 & 全局注册
npm install pinia
// main.ts
import { createSSRApp } from'vue'
import App from'./App.vue'
import { createPinia } from'pinia'
exportfunctioncreateApp() {
const app = createSSRApp(App)
app.use(createPinia())
return { app }
}
6.2 定义 Store + 持久化
// stores/user.ts
import { defineStore } from'pinia'
exportconst useUserStore = defineStore('user', {
state: () => ({
token: '',
userInfo: nullas { name: string } | null
}),
getters: { isLogin: s => !!s.token },
actions: {
login(token: string, userInfo: any) {
this.token = token
this.userInfo = userInfo
// 持久化到本地存储
uni.setStorageSync('userStore', { token, userInfo })
},
init() {
// 启动时读取本地数据
const data = uni.getStorageSync('userStore')
data && Object.assign(this, data)
}
}
})
七、❌ 6 大高频坑点 + 解决方案
开发中 90% 的报错都在这,直接对照解决👇
onLoad 获取 DOM 为 0 → 移到 onReady/nextTick TS 找不到 @dcloudio/uni-app → 安装 @dcloudio/types并配置 tsconfigPinia 数据不更新 → 不要把 store 值复制到本地 data 存储对象类型丢失 → 使用类型断言 as User | null事件总线重复触发 → onUnload 必须 uni.$offURL 传参对象丢失 → 用 JSON.stringify+encodeURIComponent
八、🛒 完整实战:商城小程序 Demo
直接套用以下结构,快速开发上线👇
src/
├── api/ # 接口请求
├── components/ # 公共组件
├── pages/ # 页面(首页/登录/详情)
├── stores/ # Pinia状态
├── utils/ # 工具类
└── pages.json # 路由配置
核心代码亮点
商品列表下拉加载更多 类型安全的商品接口定义 用户登录状态持久化 页面跳转 & 参数传递
九、✨ 最后总结
从 Vue3 切换 UniApp,核心是理解平台差异,而非照搬 Web 开发逻辑:
生命周期用onReady替代 onMounted 操作 DOM 路由传参靠onLoad,放弃 Vue Router 请求用uni.request,存储用uni.setStorageSync Pinia 正常用,记得配合uni 存储做持久化
吃透这篇,你写 UniApp 就和写普通 Vue3 一样丝滑~
夜雨聆风