简介
本技术文档围绕 DouPHP 小程序的页面架构设计,系统性说明分层架构、生命周期管理、数据绑定机制、事件处理模式、不同类型页面的实现规范、页面间通信机制、性能优化策略以及最佳实践与常见问题解决方案。文档基于仓库中默认小程序模板(miniprogram/default)的实际代码进行分析与总结,确保内容可落地、可复用。
项目结构
小程序采用“应用层 + Store 状态层 + 服务层 + 工具层 + 页面层”的分层组织方式:
- 应用层:App 入口负责全局初始化、拦截器注册、推广解析、自动更新、全局错误钩子等。
- 状态层:基于 MobX 的 store(authStore、cartStore、commonStore),提供跨页面共享状态与统一刷新策略。
- 服务层:统一 HTTP 封装,负责信封解析、缓存、去重、拦截器、错误处理等。
- 工具层:命名路由生成、UI 提示、国际化、环境判断等。
- 页面层:按业务模块划分 pages,遵循统一的加载、渲染、事件处理模式。
graph TB
App["应用入口<br/>app.ts"] --> Stores["状态聚合与引导<br/>stores/index.ts"]
App --> Http["HTTP 服务<br/>services/http.ts"]
Stores --> Auth["认证状态<br/>stores/auth.ts"]
Stores --> Cart["购物车状态"]
Stores --> Common["通用状态"]
Pages["页面集合<br/>pages/*"] --> Http
Pages --> Stores
Utils["工具集<br/>utils/route.ts 等"] --> Pages
Config["应用配置<br/>app.json"] --> Pages
核心组件
- 应用入口(App)
- 职责:注册 HTTP 拦截器、启动全局 store、解析推广参数、自动更新、全局错误与未处理 Promise 拒绝捕获、页面不存在钩子。
- 关键点:onLaunch 内完成 http.onError 统一登出、bootstrapStores 秒开、设备信息计算导航栏高度、autoUpdate 检查更新。
- 状态聚合(stores/index.ts)
- 职责:聚合 commonStore、authStore、cartStore;在 onLaunch 时先 hydrate(storage 冷启动)、再 refresh/restore(网络刷新);统一驱动 tabBar 购物车角标。
- HTTP 服务(services/http.ts)
- 职责:标准信封解析(code/message/data/errors/request_id)、默认头注入(含 Authorization)、请求/成功/失败拦截器、GET 去重、内存缓存+TTL、调试增强(request_id 装饰、异常弹窗)。
- 关键点:ApiError 统一错误对象;clearCache 支持按前缀清理;put/del 通过 _method 伪装兼容 PHP。
- 认证状态(stores/auth.ts)
- 职责:登录态持久化(api_token、user_id、loginEd)、用户模块开关降级、ensureLogin 守卫跳转、logout 清理状态。
- 命名路由(utils/route.ts)
- 职责:根据后端同步生成的路由表生成前端 URL,支持占位符替换与 query 拼接,兼容 rewrite_enable 开关。
架构总览
小程序整体采用“应用初始化 → 状态预热 → 页面按需加载 → 统一 HTTP 访问 → 状态驱动 UI”的闭环架构。页面通过 MobX 绑定 store 字段,store 变化驱动视图更新;所有网络请求经 http 层统一处理,保证错误一致性与可观测性。
sequenceDiagram
participant U as "用户"
participant P as "页面"
participant S as "Store(状态)"
participant H as "HTTP服务"
participant A as "后端API"
U->>P : 打开页面
P->>S : 绑定字段 / 触发刷新
P->>H : get/post(route(...), data, opts)
H->>A : 发送请求(带Authorization)
A-->>H : 返回信封(code/message/data)
H-->>P : resolve(data) 或 reject(ApiError)
P->>S : setData / action 更新状态
S-->>P : 响应式更新视图
详细组件分析
应用生命周期与全局初始化
- onLaunch
- 注册 http.onError 统一处理 UNAUTHORIZED 登出。
- 解析推广 user_sn 并落本地缓存。
- bootstrapStores 执行 hydrate → refresh → restore,保障首屏秒开与数据一致性。
- 计算导航栏高度,启用自动更新,非正式版开启 vConsole。
- onShow
- 从后台切回前台时再次尝试解析推广参数。
- onError / onUnhandledRejection / onPageNotFound
- 统一日志记录与调试期弹窗提示,便于定位问题。
flowchart TD
Start(["App.onLaunch"]) --> ParsePromo["解析推广参数"]
ParsePromo --> Bootstrap["bootstrapStores()"]
Bootstrap --> Hydrate["hydrate 从 storage 恢复"]
Hydrate --> Refresh["refresh/restore 网络刷新"]
Refresh --> CalcNav["计算导航栏高度"]
CalcNav --> AutoUpdate["检查更新"]
AutoUpdate --> End(["完成"])
数据绑定与状态管理(MobX)
- 使用 createStoreBindings 将 store 字段映射到 Page.data,实现响应式更新。
- stores/index.ts 在应用启动时统一 hydrate 与 refresh,避免重复请求与状态不一致。
- cartStore.badge 通过 autorun 驱动 tabBar 角标,解耦各页面 setTabBarBadge 调用。
classDiagram
class CommonStore {
+site
+lang
+data
+param
+features
+nav_list
+hydrate()
+refresh()
}
class AuthStore {
+api_token
+user_id
+loginEd
+is_login
+is_vip
+is_work
+is_distribution
+hydrate()
+restore()
+ensureLogin()
+login()
+logout()
}
class CartStore {
+badge
+refresh()
+reset()
}
CommonStore <.. AuthStore : "features 控制降级"
CommonStore <.. CartStore : "features 控制降级"
统一 HTTP 层与错误处理
- 信封解析:仅读取 code/message/data/errors/request_id,code === 'OK' 视为成功。
- 默认头:Content-Type=application/x-www-form-urlencoded、Authorization: Bearer <api_token>。
- 拦截器:onRequest/onSuccess/onError 可扩展,app.ts 已注册 UNAUTHORIZED 登出。
- 缓存与去重:GET 支持 cache/ttl/revalidate;相同 GET 飞行中复用 Promise。
- 错误对象:统一 ApiError,包含 code/statusCode/errors/data/request_id。
- 调试增强:request_id 装饰、服务端异常堆栈弹窗(仅调试环境)。
sequenceDiagram
participant P as "页面"
participant H as "HTTP服务"
participant C as "缓存/去重"
participant A as "后端API"
P->>H : get/post(url, data, opts)
H->>C : 检查缓存/去重
alt 命中缓存
C-->>P : 直接返回 data
else 未命中
H->>A : 发送请求(带Authorization)
A-->>H : 返回信封
H->>H : 解析信封/错误处理
H->>C : 写入缓存(可选)
H-->>P : resolve(data) 或 reject(ApiError)
end
列表页(首页)实现规范
- 生命周期
- onLoad:设置标题、显示分享菜单、绑定 store 字段、拉取首页数据、加载商品列表。
- onReady:恢复认证状态,若为工作人员则跳转工作台。
- onReachBottom:分页追加,防抖避免频繁请求。
- 数据流
- 通过 route('index') 获取分类与站点信息;通过 route('product') 分页加载商品列表。
- 分类横滑进度条通过 nextTick 查询节点尺寸计算百分比。
- 交互
- 分类点击 switchTab 至产品中心;普通链接 navigateTo。
flowchart TD
Load["onLoad"] --> FetchIndex["获取首页数据"]
FetchIndex --> InitList["初始化商品列表"]
InitList --> ReachBottom{"触底?"}
ReachBottom --> |是| Append["追加下一页"]
ReachBottom --> |否| Idle["等待交互"]
Append --> UpdateUI["更新列表与状态"]
UpdateUI --> ReachBottom
详情页(商品详情)实现规范
- 生命周期
- onShow:在未安装订单模块时短路,避免 route() 抛错;否则拉取购物车数量。
- onLoad:解析 id/item_id/product_id,设置标题,绑定 store 字段,拉取商品详情、属性列表、评论列表。
- 数据流
- 通过 route('product.show', {id}) 获取详情;route('product.attribute_list') 获取属性与价格盒;route('comment.list') 分页评论。
- 交互
- 加入购物车/立即购买:需 ensureLogin 校验,成功后根据 mode 跳转 checkout 或购物车 tab。
- 收藏、领券:调用对应接口并更新本地 favorites/coupon_list。
- 图片自适应:监听 imageLoad 动态计算高度。
sequenceDiagram
participant P as "商品详情页"
participant H as "HTTP服务"
participant A as "后端API"
P->>H : get(route('product.show'), {id})
H-->>P : 返回 product/favorites/open 等
P->>H : get(route('product.attribute_list'), {id, mode, attribute_data})
H-->>P : 返回 attribute_list/box
P->>H : get(route('comment.list'), {module, item_id, page})
H-->>P : 返回 comment_list
P->>H : post(route('order.cart.store'), {post, mode, action})
H-->>P : 跳转 checkout 或购物车
表单页与功能页(以会员中心为例)
- 生命周期
- onLoad:设置标题、绑定 store 字段。
- onShow:拉取用户中心数据(用户信息、认证标志、VIP/工作/分销信息),刷新购物车角标。
- 交互
- 退出登录:清空 storage、调用 authStore.logout、重置 cartStore,返回首页。
- 下载图片/复制文本:封装 wx.downloadFile/wx.setClipboardData,统一提示与错误处理。
- 导航:非 tabBar 页面使用 navigateTo,携带参数。
flowchart TD
Show["onShow"] --> FetchUser["获取用户中心数据"]
FetchUser --> BindUI["绑定 dou/user/auth/vip/work/distribution"]
BindUI --> Actions{"用户操作"}
Actions --> Logout["退出登录"]
Actions --> Download["下载图片"]
Actions --> Copy["复制文本"]
Actions --> Nav["页面导航"]
页面间通信机制
- 参数传递
- 通过 route(name, params) 生成 URL,支持路径占位符与 query 参数;页面 onLoad(options) 解析参数。
- 数据共享
- 使用 store 进行跨页面共享(如 authStore、cartStore、commonStore),通过 createStoreBindings 绑定到页面。
- 状态同步
- 通过 autorun/observable 实现响应式更新;例如 cartStore.badge 驱动 tabBar 角标。
- 推广参数
- App 在 onLaunch/onShow 解析 scene/query 中的 user_sn 并写入本地存储,供后续流程使用。
依赖关系分析
- 页面依赖
- 页面依赖 services/http.ts 发起请求,依赖 utils/route.ts 生成 URL,依赖 stores/* 管理状态。
- 应用依赖
- App 依赖 stores/index.ts 初始化状态,依赖 services/http.ts 注册全局错误处理。
- 状态依赖
- authStore 依赖 commonStore.features 控制模块降级;cartStore 依赖 tabBar 能力。
- 外部依赖
- 微信 API(wx.request、wx.navigateTo、wx.setStorageSync 等)。
graph LR
IndexPage["首页页面"] --> Http["HTTP服务"]
ProductPage["商品详情页"] --> Http
UserPage["会员中心"] --> Http
Http --> Route["命名路由"]
Http --> Stores["状态层"]
Stores --> Auth["认证状态"]
Stores --> Cart["购物车状态"]
Stores --> Common["通用状态"]
性能考虑
- 懒加载与分页
- 列表页与详情页评论采用分页加载,onReachBottom 触发追加,减少首屏数据量。
- 缓存机制
- HTTP 层对 GET 请求支持内存缓存与 TTL,revalidate 强制刷新;clearCache 支持按前缀清理。
- 去重请求
- 相同 GET 请求在飞行中复用同一 Promise,避免重复网络开销。
- 状态预热
- bootstrapStores 先 hydrate(storage 冷启动),再 refresh/restore(网络刷新),提升首屏速度。
- 资源与渲染
- 图片自适应高度,避免布局抖动;swiper 滑动与进度条计算使用 nextTick 与节点尺寸查询。
- 内存管理
- 页面卸载时销毁 storeBindings,避免内存泄漏;cartStore 提供 reset 方法用于退出登录场景。
故障排查指南
- 统一错误处理
- HTTP 层抛出 ApiError,包含 code/statusCode/errors/data/request_id;app.ts 中 onLaunch 注册 onError 处理 UNAUTHORIZED 登出。
- 调试增强
- 调试环境下,http 层对服务端异常堆栈弹出 modal,并附带 request_id 尾号;App.onError 与 onUnhandledRejection 输出日志。
- 页面不存在
- onPageNotFound 记录 path,调试期弹窗提示,便于发现拼写错误。
- 常见错误定位
- 网络异常:NETWORK_ERROR;HTTP 异常:HTTP_状态码;业务异常:服务端 code 非 OK。
- 认证失效:UNAUTHORIZED,触发 logout 并清空凭证。
结论
DouPHP 小程序采用清晰的分层架构与统一的服务封装,结合 MobX 状态管理与命名路由,实现了高内聚、低耦合的页面开发模式。通过缓存、去重、预热等策略保障性能,通过统一错误处理与调试增强提升可维护性。建议在新增页面时遵循本文档的模式与规范,确保一致性与可演进性。
附录
- 页面类型与实现要点
- 列表页:分页加载、触底追加、分类横滑进度条。
- 详情页:参数解析、属性联动、评论分页、收藏/领券。
- 表单页:输入校验、提交反馈、错误提示。
- 功能页:权限校验、模块开关降级、导航与工具函数。
- 最佳实践
- 使用 route(name, params) 生成 URL,避免硬编码路径。
- 通过 store 管理跨页面状态,避免散落的 globalData。
- 使用 http.get/post 统一封装,避免直接调用 wx.request。
- 在 onUnload 销毁 storeBindings,防止内存泄漏。
- 合理使用缓存与 revalidate,平衡实时性与性能。