文档目录
组件架构设计

简介

本文件面向 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 页面查看最近请求信息
添加日期:2026-10-05