简介
本文件面向 DouPHP 小程序的“组件架构设计”,围绕组件分类、目录规范、通信机制、生命周期与状态管理、样式隔离、注册与依赖注入、事件系统、最佳实践、性能优化、测试与调试等方面,给出系统化说明。文档基于仓库中 miniprogram/default 的实际实现进行解读,确保内容可追溯、可落地。
项目结构
小程序采用“多主题/多站点”组织方式,当前以 default 为例:
- 入口与全局配置
- app.ts:应用启动、全局错误处理、自动更新、推广解析、HTTP 拦截器挂载、Store 引导
- app.json:页面路由、全局 usingComponents 注册(如 navbar)、tabBar 配置、窗口样式
- 组件
- components/navbar:通用导航栏组件(属性、数据、生命周期、方法)
- components/mp-html:富文本渲染组件(复用第三方库)
- 服务层
- services/http.ts:统一 HTTP 封装(信封解析、缓存/去重、拦截器、错误对象)
- services/bootstrap.ts / lang.ts:启动数据与语言包拉取(被 commonStore 使用)
- 状态管理
- stores/index.ts:Store 聚合与引导(hydrate -> refresh -> restore)
- stores/auth.ts:登录态 Store(持久化、恢复、模块降级)
- stores/common.ts:公共数据 Store(种子数据、SWR 刷新、features 暴露)
- 工具与类型
- utils/*:环境判断、路由、UI 辅助等
- types/*:API 信封、Store 类型定义
graph TB
A["App(入口)"] --> B["HTTP 服务(http.ts)"]
A --> C["Store 引导(stores/index.ts)"]
C --> D["公共数据(common.ts)"]
C --> E["登录态(auth.ts)"]
A --> F["全局配置(app.json)"]
F --> G["全局组件(usingComponents)"]
G --> H["导航栏组件(navbar.ts)"]
图表来源
- app.ts:12-62
- app.json:143-145
- http.ts:195-339
- stores/index.ts:50-60
- stores/common.ts:48-105
- stores/auth.ts:69-155
- navbar.ts:7-78
章节来源
- app.ts:12-62
- app.json:136-178
核心组件
- 导航栏组件(navbar)
- 作用:提供标题、背景色、返回/首页跳转、调试入口等能力;读取全局状态计算导航栏高度
- 特性:支持多插槽、属性观察器、生命周期 attached 控制调试入口显示
- 富文本组件(mp-html)
- 作用:在小程序中渲染 HTML 内容(复用成熟方案)
- 全局组件注册
- 通过 app.json 的 usingComponents 将 navbar 注册为全局可用组件,便于各页面直接引用
章节来源
- navbar.ts:7-78
- navbar.json:1-3
- app.json:143-145
架构总览
整体架构遵循“入口初始化 -> 状态引导 -> 网络请求 -> 视图渲染”的分层模式:
- 入口 App 负责:
- 挂载 HTTP 错误拦截器(UNAUTHORIZED 登出)
- 解析推广参数并落盘
- 启动 Store(hydrate -> refresh -> restore)
- 设备信息收集、自动更新、调试开关
- 状态层(Stores):
- commonStore:种子数据 + SWR 刷新,暴露 features 供模块降级
- authStore:登录态持久化与恢复,按 features.user 决定是否发起用户接口
- cartStore:购物车角标由 autorun 驱动 tabBar 徽标
- 网络层(HTTP):
- 统一信封解析、缓存/去重、拦截器链、错误对象 ApiError
- 组件层:
- 通过 properties/data/lifetimes/methods 组织 UI 逻辑,配合 Store 与 HTTP 完成交互
sequenceDiagram
participant U as "用户"
participant APP as "App(入口)"
participant STORE as "Store 引导"
participant HTTP as "HTTP 服务"
participant API as "后端 API"
participant UI as "页面/组件"
U->>APP : 启动小程序
APP->>STORE : bootstrapStores()
STORE->>STORE : hydrate(从 storage 恢复)
STORE->>HTTP : refresh()/restore()
HTTP->>API : 获取启动数据/用户信息
API-->>HTTP : 标准信封响应
HTTP-->>STORE : data/错误
STORE-->>UI : 触发视图更新
APP->>APP : onError/onPageNotFound/自动更新
图表来源
- app.ts:23-62
- stores/index.ts:50-60
- http.ts:195-339
详细组件分析
导航栏组件(navbar)
- 结构与职责
- properties:title、backgroundColor、titleColor、scrollOpacity、url、showMenu
- data:statusBarHeight、navigationBarHeight 等,来源于 app.globalData
- lifetimes.attached:根据环境与服务器调试标志控制调试入口可见性
- methods:goBack、goHome、openDebug
- 与全局状态的关系
- 读取全局导航栏高度,保证在不同机型下布局一致
- 可通过 url 属性结合 douPageTo 进行页面跳转
- 生命周期
- attached:用于条件渲染调试入口点
classDiagram
class Navbar {
+properties : title, backgroundColor, titleColor, scrollOpacity, url, showMenu
+data : statusBarHeight, navigationBarHeight, ...
+lifetimes.attached()
+methods : goBack(), goHome(), openDebug()
}
图表来源
- navbar.ts:7-78
章节来源
- navbar.ts:7-78
- navbar.json:1-3
HTTP 服务(统一网络层)
- 职责
- 信封解析:code === 'OK' 视为成功,否则构造 ApiError
- 默认头注入:Content-Type、Authorization(Bearer token)
- 拦截器:onRequest/success/error 三阶段扩展点
- 缓存与去重:内存缓存 + TTL;相同 GET 飞行中复用 Promise
- 调试增强:request_id 追踪、异常堆栈弹窗(仅调试环境)
- 关键流程
- request/get/post/put/del:统一入口,PUT/DELETE 通过 _method 伪装
- clearCache:按前缀或清空全部缓存
- getLastRequestId:最近一次请求 ID,便于问题定位
flowchart TD
Start(["进入 request"]) --> BuildCfg["构建请求配置<br/>注入默认头"]
BuildCfg --> Interceptors{"执行请求拦截器"}
Interceptors --> CacheCheck{"是否命中缓存?"}
CacheCheck --> |是| ReturnCache["返回缓存数据"]
CacheCheck --> |否| DedupeCheck{"GET 且去重开启?<br/>是否有进行中请求?"}
DedupeCheck --> |是| UseInflight["复用进行中 Promise"]
DedupeCheck --> |否| DoRequest["发起 wx.request"]
DoRequest --> ParseEnvelope["解析信封"]
ParseEnvelope --> Ok{"code==='OK'?"}
Ok --> |否| ErrFlow["构造 ApiError<br/>执行错误拦截器"]
Ok --> |是| SuccessFlow["附加元信息<br/>写入缓存/执行成功拦截器"]
ErrFlow --> End(["结束"])
SuccessFlow --> End
图表来源
- http.ts:195-339
- http.ts:341-389
章节来源
- http.ts:19-148
- http.ts:195-339
- http.ts:341-403
Store 体系(状态管理)
- 引导流程(bootstrapStores)
- 先 hydrate(storage 秒开),再 refresh(网络刷新),最后 restore(恢复登录态)
- 绑定购物车角标(autorun 监听 badge 变化)
- commonStore
- 种子数据 + SWR 刷新,合并语言包,暴露 features 供模块降级
- authStore
- 登录态持久化(api_token/user_id/loginEd)
- restore 时按 features.user 决定是否调用用户接口
- ensureLogin 未登录则跳转登录页
- login/logout 同步持久化与状态
sequenceDiagram
participant APP as "App"
participant IDX as "stores/index"
participant COM as "commonStore"
participant AUTH as "authStore"
participant HTTP as "http"
APP->>IDX : bootstrapStores()
IDX->>COM : hydrate()
IDX->>AUTH : hydrate()
IDX->>COM : refresh()
COM->>HTTP : fetchBootstrap()
HTTP-->>COM : BootstrapData
COM-->>IDX : ready=true
IDX->>AUTH : restore()
AUTH->>HTTP : user/index(受 features.user 控制)
HTTP-->>AUTH : AuthFlags
AUTH-->>IDX : is_login/is_vip/...
图表来源
- stores/index.ts:50-60
- stores/common.ts:81-105
- stores/auth.ts:91-115
章节来源
- stores/index.ts:1-61
- stores/common.ts:48-105
- stores/auth.ts:69-155
组件间通信机制
- 父到子:通过 properties 传递配置(如 navbar 的 title/url/showMenu)
- 子到父:通过 Component 的 triggerEvent(可在页面监听自定义事件)
- 跨层级/全局:
- 全局 Store(MobX):commonStore/authStore/cartStore 作为单一真相源
- 全局 HTTP 拦截器:onError 统一处理 UNAUTHORIZED 登出
- 全局 App 钩子:onError/onUnhandledRejection/onPageNotFound 统一兜底
章节来源
- navbar.ts:12-38
- app.ts:23-35
- stores/index.ts:20-42
生命周期管理
- 组件生命周期
- navbar 使用 lifetimes.attached 控制调试入口渲染
- 应用生命周期
- onLaunch:初始化 Store、设备信息、自动更新、调试开关
- onShow:再次尝试解析推广参数
- onError/onUnhandledRejection/onPageNotFound:统一错误与调试提示
章节来源
- navbar.ts:50-57
- app.ts:23-96
状态管理机制
- 数据源
- 本地存储:api_token、user_id、loginEd、common 启动数据
- 网络数据:bootstrap 与用户信息
- 状态模型
- commonStore:site/lang/features/nav_list/data/version/ready
- authStore:api_token/user_id/loginEd/is_login/is_vip/is_work/is_distribution
- cartStore:badge(驱动 tabBar 徽标)
- 更新策略
- SWR:先 hydrate 展示,再 refresh 覆盖
- autorun:cartStore.badge 变化自动更新 tabBar 徽标
章节来源
- stores/common.ts:48-105
- stores/auth.ts:69-155
- stores/index.ts:20-42
样式隔离方案
- 组件级样式隔离
- 微信小程序原生样式隔离:每个组件拥有独立样式作用域,避免污染
- 全局样式
- app.wxss 提供全局基础样式(本项目中未展开具体样式)
- 建议
- 组件内样式尽量局部化,避免全局选择器
- 使用命名空间或 BEM 风格类名减少冲突
组件注册机制与依赖注入
- 组件注册
- 通过 app.json 的 usingComponents 将 navbar 注册为全局组件
- 依赖注入
- 通过 Store 与 HTTP 服务解耦业务与基础设施
- 组件通过访问全局 Store(如 app.globalData)与工具函数(如 douPageTo)完成行为
章节来源
- app.json:143-145
- navbar.ts:5-6
事件系统
- 自定义事件
- 组件可使用 triggerEvent 向父组件派发事件(页面侧监听)
- 全局事件
- HTTP 拦截器:onError 统一处理认证失效
- App 钩子:onError/onUnhandledRejection/onPageNotFound 统一捕获异常
章节来源
- http.ts:391-400
- app.ts:69-96
依赖关系分析
- 入口依赖
- app.ts 依赖 http、stores、utils/env、config/site
- Store 依赖
- stores/index.ts 依赖 mobx-miniprogram、utils/tabbar、authStore/cartStore/commonStore
- stores/auth.ts 依赖 http、utils/promotion/route、commonStore
- stores/common.ts 依赖 bootstrap/lang、persist、seed.generated
- 组件依赖
- navbar 依赖 utils/env、utils/ui、app.globalData
graph LR
APP["app.ts"] --> HTTP["services/http.ts"]
APP --> STI["stores/index.ts"]
STI --> AUTH["stores/auth.ts"]
STI --> COM["stores/common.ts"]
NAV["components/navbar/navbar.ts"] --> ENV["utils/env.ts"]
NAV --> UI["utils/ui.ts"]
图表来源
- app.ts:5-10
- stores/index.ts:5-13
- stores/auth.ts:8-13
- stores/common.ts:8-14
- navbar.ts:2-3
章节来源
- app.ts:5-10
- stores/index.ts:5-13
- stores/auth.ts:8-13
- stores/common.ts:8-14
- navbar.ts:2-3
性能考量
- 首屏体验
- SWR:先 hydrate 展示种子/缓存数据,再网络刷新
- 冷启动优化:store.hydrate 零等待渲染
- 网络优化
- GET 去重:inflight 复用进行中请求
- 内存缓存:cache+ttl 减少重复请求
- 方法伪装:PUT/DELETE 通过 _method 兼容 PHP 接收
- 渲染优化
- 购物车角标 autorun 集中更新,避免多处 setTabBarBadge
- 调试与可观测性
- request_id 追踪、异常堆栈弹窗(仅调试环境)
章节来源
- stores/index.ts:50-60
- http.ts:217-236
- http.ts:303-315
- http.ts:355-364
- stores/index.ts:20-42
故障排查指南
- 常见问题定位
- 网络错误:查看 ApiError.code/message/errors/request_id,必要时复制堆栈
- 认证失效:HTTP onError 拦截器会触发登出,检查 api_token 与用户接口
- 页面不存在:onPageNotFound 打印 path,调试期弹窗提示
- JS 异常:onError 打印错误,调试期弹窗
- 调试手段
- 非正式版开启 vConsole
- 服务端异常载荷(errors.exception/file/line/trace)弹窗并支持复制
- 使用 getLastRequestId 关联前后端日志
章节来源
- http.ts:133-175
- http.ts:317-339
- app.ts:58-96
结论
DouPHP 小程序的组件架构以“分层清晰、职责单一”为核心:
- 入口负责初始化与全局异常处理
- Store 层提供统一状态与 SWR 刷新策略
- HTTP 层提供健壮的网络抽象与调试能力
- 组件层聚焦 UI 与交互,通过 Store 与 HTTP 完成数据与行为 该架构具备良好的可扩展性与可维护性,适合复杂业务场景下的持续演进。
附录
- 组件开发最佳实践
- 明确 props 与 data 边界,避免在组件内直接修改外部状态
- 使用 lifetimes 管理资源与副作用
- 通过 Store 共享状态,避免跨组件耦合
- 性能优化建议
- 合理使用 cache/ttl,避免频繁请求
- 利用 autorun 集中更新 UI 相关的全局状态
- 谨慎使用全局样式,优先组件内样式
- 测试策略
- 单元测试:对 Store actions、HTTP 拦截器进行断言
- 集成测试:模拟网络响应验证组件渲染与交互
- 回归测试:关注 SWR 刷新后的状态一致性
- 调试方法
- 借助 request_id 与后端日志联动
- 调试期启用 vConsole 与异常弹窗
- 使用 pages/debug 页面查看最近请求信息