第19集:uni-app 大型应用架构
章节概览
在本章节中,我们将学习如何构建 uni-app 大型应用架构。随着应用规模的不断扩大,良好的架构设计变得越来越重要。通过本章节的学习,您将掌握状态管理、路由管理、模块化开发等核心知识点,并能够构建可维护、可扩展的大型应用架构。
核心知识点
1. 状态管理
状态管理是大型应用架构中的核心部分,用于管理应用的全局状态。uni-app 中常用的状态管理方案包括:
- Vuex:Vue 官方推荐的状态管理库,适用于中大型应用
- Pinia:Vue 3 官方推荐的状态管理库,提供了更简洁的 API
- 简单状态管理:适用于小型应用的简单状态管理方案
2. 路由管理
路由管理负责应用的页面导航和页面状态管理,包括:
- 路由配置:定义应用的页面路由结构
- 导航守卫:控制页面导航的权限和行为
- 路由参数:处理页面间的参数传递
- 路由元信息:存储路由相关的额外信息
3. 模块化开发
模块化开发是大型应用架构的重要组成部分,包括:
- 组件模块化:将 UI 拆分为可复用的组件
- 业务逻辑模块化:将业务逻辑拆分为独立的模块
- 工具函数模块化:将通用工具函数封装为独立的模块
- API 模块化:将 API 请求封装为独立的模块
4. 目录结构设计
合理的目录结构设计有助于提高代码的可维护性和可读性,包括:
- 页面目录:存放应用的页面组件
- 组件目录:存放可复用的组件
- store 目录:存放状态管理相关代码
- utils 目录:存放工具函数
- api 目录:存放 API 请求相关代码
- config 目录:存放配置文件
- styles 目录:存放全局样式
实用案例
构建大型电商应用架构
我们将构建一个大型电商应用的架构,包括:
- 状态管理设计:用户状态、商品状态、购物车状态等
- 路由管理设计:权限控制、页面导航等
- 模块化设计:组件、业务逻辑、API 等模块化
- 目录结构设计:合理的目录结构组织
代码示例
1. 状态管理设计
使用 Vuex 进行状态管理
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import goods from './modules/goods'
import cart from './modules/cart'
import order from './modules/order'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
// 全局状态
loading: false,
error: null
},
mutations: {
// 设置加载状态
setLoading(state, status) {
state.loading = status
},
// 设置错误信息
setError(state, error) {
state.error = error
}
},
actions: {
// 重置错误信息
resetError({ commit }) {
commit('setError', null)
}
},
getters: {
// 获取加载状态
isLoading: state => state.loading,
// 获取错误信息
error: state => state.error
},
modules: {
user,
goods,
cart,
order
}
})用户状态模块
// store/modules/user.js
export default {
namespaced: true,
state: {
userInfo: null,
token: null,
isLoggedIn: false
},
mutations: {
// 设置用户信息
setUserInfo(state, userInfo) {
state.userInfo = userInfo
state.isLoggedIn = true
},
// 设置 token
setToken(state, token) {
state.token = token
},
// 清除用户信息
clearUserInfo(state) {
state.userInfo = null
state.token = null
state.isLoggedIn = false
}
},
actions: {
// 登录
async login({ commit }, loginData) {
try {
// 调用登录 API
const response = await uniCloud.callFunction({
name: 'login',
data: loginData
})
if (response.result.code === 200) {
// 保存用户信息和 token
commit('setUserInfo', response.result.data.user)
commit('setToken', response.result.data.token)
// 存储到本地存储
uni.setStorageSync('userInfo', response.result.data.user)
uni.setStorageSync('token', response.result.data.token)
return true
} else {
throw new Error(response.result.message)
}
} catch (error) {
console.error('登录失败:', error)
throw error
}
},
// 登出
logout({ commit }) {
// 清除用户信息
commit('clearUserInfo')
// 清除本地存储
uni.removeStorageSync('userInfo')
uni.removeStorageSync('token')
},
// 初始化用户状态
initUserState({ commit }) {
// 从本地存储读取用户信息
const userInfo = uni.getStorageSync('userInfo')
const token = uni.getStorageSync('token')
if (userInfo && token) {
commit('setUserInfo', userInfo)
commit('setToken', token)
}
}
},
getters: {
// 获取用户信息
userInfo: state => state.userInfo,
// 获取 token
token: state => state.token,
// 是否登录
isLoggedIn: state => state.isLoggedIn
}
}商品状态模块
// store/modules/goods.js
export default {
namespaced: true,
state: {
goodsList: [],
goodsDetail: null,
currentPage: 1,
pageSize: 10,
total: 0,
loading: false
},
mutations: {
// 设置商品列表
setGoodsList(state, goodsList) {
state.goodsList = goodsList
},
// 添加商品列表(用于分页加载)
addGoodsList(state, goodsList) {
state.goodsList = [...state.goodsList, ...goodsList]
},
// 设置商品详情
setGoodsDetail(state, goodsDetail) {
state.goodsDetail = goodsDetail
},
// 设置当前页码
setCurrentPage(state, currentPage) {
state.currentPage = currentPage
},
// 设置总条数
setTotal(state, total) {
state.total = total
},
// 设置加载状态
setLoading(state, loading) {
state.loading = loading
}
},
actions: {
// 获取商品列表
async getGoodsList({ commit, state }, params = {}) {
try {
commit('setLoading', true)
const response = await uniCloud.callFunction({
name: 'getGoodsList',
data: {
page: params.page || state.currentPage,
pageSize: params.pageSize || state.pageSize,
...params
}
})
if (response.result.code === 200) {
if (params.page === 1 || !params.page) {
commit('setGoodsList', response.result.data.list)
} else {
commit('addGoodsList', response.result.data.list)
}
commit('setCurrentPage', params.page || state.currentPage)
commit('setTotal', response.result.data.total)
return response.result.data
} else {
throw new Error(response.result.message)
}
} catch (error) {
console.error('获取商品列表失败:', error)
throw error
} finally {
commit('setLoading', false)
}
},
// 获取商品详情
async getGoodsDetail({ commit }, goodsId) {
try {
commit('setLoading', true)
const response = await uniCloud.callFunction({
name: 'getGoodsDetail',
data: { goodsId }
})
if (response.result.code === 200) {
commit('setGoodsDetail', response.result.data)
return response.result.data
} else {
throw new Error(response.result.message)
}
} catch (error) {
console.error('获取商品详情失败:', error)
throw error
} finally {
commit('setLoading', false)
}
}
},
getters: {
// 获取商品列表
goodsList: state => state.goodsList,
// 获取商品详情
goodsDetail: state => state.goodsDetail,
// 是否还有更多商品
hasMore: state => state.goodsList.length < state.total,
// 加载状态
loading: state => state.loading
}
}2. 路由管理设计
路由配置
// pages.json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "pages/register/register",
"style": {
"navigationBarTitleText": "注册"
}
},
{
"path": "pages/goods/list",
"style": {
"navigationBarTitleText": "商品列表"
}
},
{
"path": "pages/goods/detail",
"style": {
"navigationBarTitleText": "商品详情"
}
},
{
"path": "pages/cart/index",
"style": {
"navigationBarTitleText": "购物车"
}
},
{
"path": "pages/order/list",
"style": {
"navigationBarTitleText": "订单列表"
}
},
{
"path": "pages/order/detail",
"style": {
"navigationBarTitleText": "订单详情"
}
},
{
"path": "pages/user/index",
"style": {
"navigationBarTitleText": "个人中心"
}
}
],
"subPackages": [
{
"root": "pages/admin",
"pages": [
{
"path": "index/index",
"style": {
"navigationBarTitleText": "管理后台"
}
},
{
"path": "goods/manage",
"style": {
"navigationBarTitleText": "商品管理"
}
},
{
"path": "order/manage",
"style": {
"navigationBarTitleText": "订单管理"
}
}
]
}
],
"tabBar": {
"color": "#999",
"selectedColor": "#007aff",
"borderStyle": "black",
"backgroundColor": "#fff",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home-active.png"
},
{
"pagePath": "pages/goods/list",
"text": "商品",
"iconPath": "static/tabbar/goods.png",
"selectedIconPath": "static/tabbar/goods-active.png"
},
{
"pagePath": "pages/cart/index",
"text": "购物车",
"iconPath": "static/tabbar/cart.png",
"selectedIconPath": "static/tabbar/cart-active.png"
},
{
"pagePath": "pages/user/index",
"text": "我的",
"iconPath": "static/tabbar/user.png",
"selectedIconPath": "static/tabbar/user-active.png"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app 电商",
"navigationBarBackgroundColor": "#fff",
"backgroundColor": "#f5f5f5"
}
}导航守卫
// utils/routeGuard.js
import store from '@/store'
// 白名单,无需登录即可访问的页面
const whiteList = ['/pages/login/login', '/pages/register/register', '/pages/index/index', '/pages/goods/list', '/pages/goods/detail']
// 路由守卫
export function routeGuard() {
// 监听页面加载
uni.addInterceptor('navigateTo', {
invoke: (args) => {
// 检查是否需要登录
if (!whiteList.includes(args.url) && !store.state.user.isLoggedIn) {
uni.navigateTo({
url: '/pages/login/login'
})
return false
}
return true
}
})
// 监听页面重定向
uni.addInterceptor('redirectTo', {
invoke: (args) => {
// 检查是否需要登录
if (!whiteList.includes(args.url) && !store.state.user.isLoggedIn) {
uni.navigateTo({
url: '/pages/login/login'
})
return false
}
return true
}
})
// 监听页面切换
uni.addInterceptor('switchTab', {
invoke: (args) => {
// 检查是否需要登录(这里可以根据实际需求调整)
return true
}
})
}3. 模块化开发
API 模块化
// api/index.js
import request from './request'
export const userApi = {
// 登录
login: (data) => request('login', data),
// 注册
register: (data) => request('register', data),
// 获取用户信息
getUserInfo: (data) => request('getUserInfo', data),
// 更新用户信息
updateUserInfo: (data) => request('updateUserInfo', data)
}
export const goodsApi = {
// 获取商品列表
getGoodsList: (data) => request('getGoodsList', data),
// 获取商品详情
getGoodsDetail: (data) => request('getGoodsDetail', data),
// 搜索商品
searchGoods: (data) => request('searchGoods', data)
}
export const cartApi = {
// 获取购物车列表
getCartList: (data) => request('getCartList', data),
// 添加到购物车
addToCart: (data) => request('addToCart', data),
// 更新购物车商品
updateCartItem: (data) => request('updateCartItem', data),
// 删除购物车商品
deleteCartItem: (data) => request('deleteCartItem', data)
}
export const orderApi = {
// 创建订单
createOrder: (data) => request('createOrder', data),
// 获取订单列表
getOrderList: (data) => request('getOrderList', data),
// 获取订单详情
getOrderDetail: (data) => request('getOrderDetail', data),
// 更新订单状态
updateOrderStatus: (data) => request('updateOrderStatus', data)
}请求封装
// api/request.js
import store from '@/store'
// 请求封装
export default async function request(name, data = {}) {
try {
// 显示加载状态
store.commit('setLoading', true)
// 调用云函数
const response = await uniCloud.callFunction({
name,
data: {
// 添加 token 等公共参数
token: store.state.user.token,
...data
}
})
// 处理响应
if (response.result.code === 200) {
return response.result.data
} else if (response.result.code === 401) {
// 未登录或 token 过期
store.dispatch('user/logout')
uni.navigateTo({
url: '/pages/login/login'
})
throw new Error('请重新登录')
} else {
throw new Error(response.result.message || '请求失败')
}
} catch (error) {
console.error('请求失败:', error)
throw error
} finally {
// 隐藏加载状态
store.commit('setLoading', false)
}
}工具函数模块化
// utils/index.js
export * from './storage'
export * from './validate'
export * from './format'
export * from './request'
export * from './routeGuard'// utils/storage.js
// 存储工具函数
export const storage = {
// 设置存储
set(key, value) {
uni.setStorageSync(key, value)
},
// 获取存储
get(key, defaultValue = null) {
try {
const value = uni.getStorageSync(key)
return value !== undefined ? value : defaultValue
} catch (error) {
console.error('获取存储失败:', error)
return defaultValue
}
},
// 删除存储
remove(key) {
uni.removeStorageSync(key)
},
// 清空存储
clear() {
uni.clearStorageSync()
}
}4. 目录结构设计
src/
├── api/ # API 模块化
│ ├── index.js # API 导出
│ └── request.js # 请求封装
├── components/ # 公共组件
│ ├── goods-card/ # 商品卡片组件
│ ├── form-item/ # 表单项目组件
│ └── modal/ # 模态框组件
├── pages/ # 页面
│ ├── index/ # 首页
│ ├── login/ # 登录页
│ ├── register/ # 注册页
│ ├── goods/ # 商品相关页面
│ ├── cart/ # 购物车页面
│ ├── order/ # 订单相关页面
│ └── user/ # 用户中心页面
├── store/ # 状态管理
│ ├── index.js # 状态管理入口
│ └── modules/ # 状态管理模块
├── styles/ # 样式
│ ├── common.css # 公共样式
│ └── variables.css # 样式变量
├── utils/ # 工具函数
│ ├── index.js # 工具函数导出
│ ├── storage.js # 存储工具
│ ├── validate.js # 验证工具
│ └── format.js # 格式化工具
├── App.vue # 应用入口组件
├── main.js # 应用入口文件
└── pages.json # 页面配置文件常见问题与解决方案
1. 状态管理复杂度
问题:应用状态管理变得越来越复杂,难以维护
解决方案:
- 合理划分状态管理模块,每个模块负责特定的业务领域
- 使用命名空间(namespaced)避免状态冲突
- 遵循单向数据流原则,保持状态管理的清晰性
- 定期清理不需要的状态,避免状态冗余
2. 路由管理混乱
问题:应用路由管理混乱,权限控制复杂
解决方案:
- 合理设计路由结构,使用子包(subPackages)优化打包体积
- 使用导航守卫统一处理权限控制
- 定义路由常量,避免硬编码路由路径
- 合理使用路由元信息,存储路由相关的额外信息
3. 模块化开发不规范
问题:模块化开发不规范,代码重复度高
解决方案:
- 制定模块化开发规范,统一代码风格
- 合理划分模块边界,避免模块间过度耦合
- 使用工具函数封装通用逻辑,减少代码重复
- 定期重构代码,优化模块结构
学习总结
通过本章节的学习,您已经掌握了以下内容:
- 状态管理:学会了使用 Vuex 进行状态管理,包括模块划分、 mutations、actions 和 getters 的使用
- 路由管理:掌握了路由配置、导航守卫、路由参数和路由元信息的使用
- 模块化开发:学会了 API 模块化、工具函数模块化等模块化开发方法
- 目录结构设计:掌握了合理的目录结构设计方法,提高代码的可维护性
- 实战应用:构建了一个大型电商应用的架构设计
良好的架构设计是大型应用成功的关键。通过合理的状态管理、路由管理和模块化开发,您可以构建出可维护、可扩展的大型应用架构。在实际项目中,您应该根据项目的具体需求和规模,选择合适的架构方案,并不断优化和调整。
在后续的学习中,我们将继续探讨 uni-app 的最佳实践,帮助您进一步提升应用开发能力。