简介
本技术文档围绕 DouPHP 小程序的页面通信模式,系统梳理并说明以下能力:
- 页面栈导航传参与跳转策略
- 全局状态共享(基于 MobX 的 Store)
- 事件总线与跨页通知(通过 Store 响应式更新驱动)
- 存储机制(本地持久化、启动时秒开、网络刷新)
- 页面状态同步机制(实时数据同步、冲突解决、版本控制)
- 跨页面数据共享最佳实践(一致性、性能、安全)
- 复杂交互场景方案(表单回填、列表筛选、购物车同步等)
目标是为开发者提供一套可落地的通信范式与实现参考,帮助在不同业务场景中选择合适的通信方式。
项目结构
DouPHP 小程序采用“应用入口 + 统一 HTTP 层 + 模块化 Store + 工具库”的分层组织:
- 应用入口负责初始化全局环境、错误处理、自动更新、推广解析与 Store 引导
- HTTP 层封装请求信封、缓存、去重、拦截器与调试钩子
- Store 层以 MobX 管理登录态、公共数据、购物车等业务状态,并通过 autorun 驱动 UI 更新
- 工具库提供命名路由生成、页面跳转决策、UI 辅助等通用能力
graph TB
App["应用入口 app.ts"] --> StoresIndex["Store 聚合 stores/index.ts"]
StoresIndex --> AuthStore["登录态 stores/auth.ts"]
StoresIndex --> CommonStore["公共数据 stores/common.ts"]
StoresIndex --> CartStore["购物车 stores/cart.ts"]
App --> Http["HTTP 服务 services/http.ts"]
StoresIndex --> Route["命名路由 utils/route.ts"]
StoresIndex --> Ui["页面跳转 utils/ui.ts"]
核心组件
- 应用入口(App):注册全局错误钩子、自动更新、推广参数解析、窗口尺寸计算;在 onLaunch 中引导 Store 初始化与预热。
- HTTP 层:统一信封解析、鉴权头注入、请求/成功/错误拦截器、内存缓存与请求去重、调试增强。
- Store 体系:
- commonStore:种子数据秒开、网络刷新、features 下发、语言包合并与持久化
- authStore:登录态持久化、模块降级、ensureLogin 统一鉴权跳转
- cartStore:购物车数量与角标联动、模块降级与未登录短路
- 工具库:
- route:命名路由生成,兼容 rewrite 开关,统一 URL 形态
- ui:智能页面跳转(回退/switchTab/redirectTo),当前页 URL 构造
架构总览
下图展示了小程序启动到页面通信的关键路径:应用启动后先 hydrate 本地数据,再刷新网络数据;Store 间通过响应式绑定驱动 UI;页面间通过命名路由与工具函数进行导航与传参;HTTP 层为所有数据访问提供一致的信封与缓存语义。
sequenceDiagram
participant U as "用户"
participant A as "应用入口 app.ts"
participant SI as "Store 聚合 stores/index.ts"
participant CS as "公共数据 stores/common.ts"
participant AS as "登录态 stores/auth.ts"
participant CTS as "购物车 stores/cart.ts"
participant H as "HTTP 服务 services/http.ts"
participant R as "命名路由 utils/route.ts"
participant UI as "页面跳转 utils/ui.ts"
U->>A : 启动小程序
A->>SI : bootstrapStores()
SI->>CS : hydrate()
SI->>AS : hydrate()
SI->>CTS : bindCartBadge()
SI->>CS : refresh()
CS->>H : fetchBootstrap()
H-->>CS : 返回信封 data
CS->>CS : applyData() + 持久化
SI->>AS : restore()
AS->>R : route('user')
AS->>H : GET /user
H-->>AS : 返回信封 data
AS->>AS : applyAuthFlags()
SI->>CTS : refresh()
CTS->>R : route('order.cart')
CTS->>H : GET /order/cart
H-->>CTS : 返回信封 data
CTS->>CTS : number = cart_number
Note over CTS,UI : autorun 触发 wx.setTabBarBadge
详细组件分析
页面栈导航传参
- 智能跳转策略:优先回退到已在页面栈的目标页;若目标是 tabBar 页则使用 switchTab;否则使用 redirectTo。
- 当前页 URL 构造:读取当前 page.route 与 options 拼装成带参数的 URL,便于分享或记录。
- 适用场景:
- 列表到详情:传递 id、分类等参数
- 搜索历史:将关键词写入 storage 并跳转到搜索结果页
- 表单回填:从详情页回退时携带回填数据
flowchart TD
Start(["调用 douPageTo(url)"]) --> CheckStack{"目标是否在页面栈"}
CheckStack --> |是| Back["wx.navigateBack(delta)"]
CheckStack --> |否| IsTab{"是否 tabBar 页"}
IsTab --> |是| Switch["wx.switchTab({url})"]
IsTab --> |否| Redirect["wx.redirectTo({url})"]
Back --> End(["完成"])
Switch --> End
Redirect --> End
全局变量共享(Store 响应式)
- 单一真相源:commonStore 作为站点信息、语言包、功能开关(features)、导航数据的唯一来源,支持 SWR 模式(Seed -> Hydrate -> Refresh)。
- 登录态共享:authStore 维护 api_token、user_id、loginEd 及业务 flags(is_login、is_vip 等),并提供 ensureLogin 统一鉴权跳转。
- 购物车共享:cartStore 暴露 number 与 badge 计算属性,配合 autorun 驱动 tabBar 角标。
- 适用场景:
- 多页面共享用户信息、站点配置、功能开关
- 跨页面同步购物车数量与角标
- 统一鉴权与降级(模块未启用时短路)
classDiagram
class CommonStore {
+site
+lang
+param
+nav_list
+features
+data
+version
+ready
+applyData(payload)
+hydrate()
+refresh()
}
class AuthStore {
+api_token
+user_id
+loginEd
+is_login
+is_vip
+is_work
+is_distribution
+hydrate()
+restore()
+ensureLogin(redirectUrl)
+login(payload)
+logout()
}
class CartStore {
+number
+badge
+refresh()
+reset()
}
CommonStore <.. AuthStore : "features 控制降级"
CommonStore <.. CartStore : "features 控制降级"
事件总线(基于 Store 的响应式通知)
- 机制说明:通过 MobX 的 observable + autorun,当 Store 状态变化时自动触发副作用(如更新 tabBar 角标、刷新列表)。
- 优势:解耦页面与数据源,避免手动派发/监听带来的耦合;天然支持批量更新与细粒度订阅。
- 典型用法:
- 购物车数量变化 -> 自动更新角标
- 登录态变化 -> 自动切换展示内容或跳转登录页
- features 变化 -> 动态启用/禁用模块相关页面
存储机制(本地持久化与启动秒开)
- 种子数据:首帧即有文案与站点名,保证冷启动体验。
- Hydrate:从 storage 恢复 commonStore、authStore 的状态,实现 0ms 冷启动。
- Refresh:网络刷新后合并语言包与 features,并写回 storage 持久化。
- 适用场景:
- 首屏快速渲染
- 离线可用(保留上次有效数据)
- 跨会话保持登录态与偏好
页面状态同步机制
- 实时数据同步:Store 的 autorun 与响应式更新确保 UI 与数据一致;HTTP 层的 dedupe 与 cache 减少重复请求。
- 冲突解决:SWR 模式(Seed -> Hydrate -> Refresh)保证最终一致性;失败时保留已有数据不打断首屏。
- 版本控制:commonStore.version 由后端下发,可用于前端缓存失效与灰度策略。
- 适用场景:
- 购物车数量与角标的实时同步
- 登录态变化后的统一鉴权跳转
- 功能开关变更后的模块级降级
跨页面数据共享最佳实践
- 数据一致性:以 Store 为单一真相源,页面仅消费状态,不直接修改共享数据;通过 action 更新。
- 性能考虑:GET 请求默认去重与内存缓存;按需 revalidate;避免频繁 setData 大对象。
- 安全性保障:Authorization 头由 HTTP 层注入;UNAUTHORIZED 统一登出;敏感数据不落盘或加密存储(根据业务需求扩展)。
- 适用场景:
- 多页面共享用户信息与权限
- 购物车跨页同步
- 功能开关驱动的页面可见性
复杂页面交互场景解决方案
- 表单回填:利用页面栈回退(navigateBack)携带参数,或使用 storage 暂存草稿,进入页面时 hydrate 并填充。
- 列表筛选:将筛选条件存入 storage 或通过路由参数传递;列表页读取后发起请求,结果缓存并去重。
- 购物车同步:cartStore.number 变化通过 autorun 更新角标;添加/删除商品后调用 refresh 拉取最新数量。
- 推荐流程:扫码/分享进入 -> onLaunch 解析 user_sn -> 写入 storage -> 后续请求携带推广标识。
依赖关系分析
- 应用入口依赖 Store 聚合与 HTTP 层;Store 聚合依赖各业务 Store;业务 Store 依赖 HTTP 层与命名路由;工具库被多处复用。
- 潜在循环依赖:Store 之间通过 commonStore.features 进行降级判断,无直接循环引用。
- 外部依赖:微信 API(wx.request、wx.getStorageSync 等)、MobX 响应式库。
graph LR
App["app.ts"] --> SI["stores/index.ts"]
SI --> CS["stores/common.ts"]
SI --> AS["stores/auth.ts"]
SI --> CTS["stores/cart.ts"]
CS --> H["services/http.ts"]
AS --> H
CTS --> H
AS --> R["utils/route.ts"]
CTS --> R
App --> UI["utils/ui.ts"]
性能考虑
- 首屏优化:种子数据 + Hydrate 实现秒开;网络失败保留已有数据。
- 请求优化:GET 去重与内存缓存;按需 revalidate;失败静默降级。
- UI 更新:autorun 细粒度订阅,避免全量刷新;角标更新集中管理。
- 建议:
- 合理使用 cache/ttl/revalidate 控制缓存策略
- 避免在高频回调中执行重计算或大量 setData
- 对大对象使用分页与虚拟列表
故障排查指南
- 统一错误处理:HTTP 层将网络异常、HTTP 非 2xx、业务码非 OK 统一为 ApiError;app 层 onError 捕获 JS 异常并在调试期弹窗。
- 鉴权失败:UNAUTHORIZED 触发登出;authStore.restore 仅在 UNAUTHORIZED 时清空 is_login,其他错误保留登录态避免弱网假登出。
- 调试增强:request_id 装饰错误消息;调试期弹出服务端异常堆栈并支持复制。
- 建议:
- 使用 getLastRequestId 关联前后端日志
- 在开发环境开启 vConsole 与调试弹窗
- 对关键路径增加埋点与错误上报
结论
DouPHP 小程序的页面通信以 Store 为核心,结合 HTTP 层与工具库,形成了一套高内聚、低耦合、可扩展的通信体系。通过 SWR 模式、响应式更新与统一错误处理,实现了高效、稳定、易维护的跨页面数据共享与状态同步。在实际项目中,应根据场景选择合适的通信方式:简单传参用页面栈导航,复杂状态用 Store,跨会话数据用存储,实时同步用响应式绑定。
附录
- 命名路由:通过 route(name, params) 生成统一 URL,兼容 rewrite 开关与 query 拼接。
- 页面跳转:douPageTo 智能决策回退/switchTab/redirectTo,适配模块化裁剪后的 tabBar。
- 启动流程:onLaunch 解析推广参数、初始化 Store、计算窗口尺寸、自动更新。