简介
本文件面向 DouPHP 小程序的商品展示能力,覆盖商品列表、商品详情、商品分类三大核心展示场景。文档从数据模型、图片处理、价格显示、库存状态等业务逻辑出发,说明组件的 props 配置(页面级参数)、事件处理、样式定制方法;并给出与后端 API 的数据交互流程、错误处理与加载状态管理策略;最后提供响应式设计与性能优化建议,帮助开发者快速集成与扩展。
项目结构
- 小程序前端位于 miniprogram/default/pages,商品相关页面包括 product(详情)与 product_category(列表/分类)。
- HTTP 请求封装在 services/http.ts,统一信封解析、缓存、去重、拦截器与错误处理。
- 后端 API 控制器位于 api/controller/product/ProductController.php,提供商品列表、详情、属性等接口。
graph TB
subgraph "小程序前端"
P["pages/product/product.ts/.wxml"]
PC["pages/product_category/product_category.ts/.wxml"]
H["services/http.ts"]
end
subgraph "后端 API"
C["api/controller/product/ProductController.php"]
end
P --> H
PC --> H
H --> C
核心组件
- 商品详情页(product)
- 负责商品主图与图集轮播、标题与价格、优惠券领取、收藏、规格属性选择、评论分页、加入购物车/立即购买、数量增减、分享标题设置等。
- 商品列表页(product_category)
- 负责左侧分类树、顶部排序筛选、商品卡片列表、分页加载、跳转详情等。
- HTTP 层(http.ts)
- 统一请求封装:信封解析、成功/失败拦截、内存缓存与 TTL、GET 去重、调试增强、request_id 追踪。
架构总览
小程序通过 http.ts 调用后端 ProductController 提供的接口,获取商品列表与详情数据,并在 WXML 中渲染。页面间通过路由参数传递 ID,统一通过 route() 生成路径。
sequenceDiagram
participant U as "用户"
participant P as "商品详情页<br/>product.ts"
participant H as "HTTP 层<br/>http.ts"
participant A as "后端控制器<br/>ProductController.php"
U->>P : 打开商品详情
P->>H : GET /product.show?id=xxx
H->>A : 发起网络请求
A-->>H : 返回标准信封 {code,message,data,...}
H-->>P : 解析后返回 data
P->>P : setData({product, coupon_list, open, ...})
P-->>U : 渲染商品详情、价格、图集、评论
详细组件分析
商品详情页(product)
- 数据加载
- onLoad 时根据 id/item_id/product_id 读取商品详情,设置标题、商品对象、定义字段、优惠券列表、功能开关等。
- 同时拉取购物车数量(若订单模块开启),用于底部购物车徽标。
- 图片处理
- 主图与图集通过 swiper 展示,imageLoad 回调根据窗口宽度与图片宽高计算高度,避免布局抖动。
- 价格显示
- 使用 sale_price.format 作为现价,sale_price.name 为促销标签,price_format/price 为原价或划线价提示。
- 当 mode 为 point 时,显示积分相关字段。
- 规格属性
- attributeList 根据当前选择的属性组合动态刷新可选属性、盒装信息与价格。
- 评论分页
- commentList 支持首次加载与加载更多,onReachBottom 触发下一页,loadpage 控制加载提示。
- 购买流程
- addToCart 提交表单(含属性、数量、模块与 item_id),根据 action 决定加入购物车或立即购买;积分模式走不同按钮分支。
- 收藏与优惠券
- favorites 切换收藏状态;getCoupon 领取优惠券并更新列表。
- 事件与导航
- douSwitchTab/douNavigateTo 用于底部导航与页面跳转;onShareAppMessage 使用本地存储的分享标题。
flowchart TD
Start(["进入商品详情"]) --> Load["加载商品详情<br/>http.get(product.show)"]
Load --> SetData{"是否成功?"}
SetData -- 否 --> Err["显示错误提示"]
SetData -- 是 --> Render["渲染图片/价格/内容/评论"]
Render --> Attr["加载属性列表"]
Render --> Comment["加载评论(第一页)"]
Attr --> UserSelect{"用户选择属性?"}
UserSelect -- 是 --> RefreshAttr["重新计算属性/价格"]
UserSelect -- 否 --> CartBar["底部购物车栏"]
Comment --> ReachBottom{"触底加载更多?"}
ReachBottom -- 是 --> LoadMore["加载下一页评论"]
ReachBottom -- 否 --> End(["结束"])
LoadMore --> End
商品列表页(product_category)
- 数据加载
- onLoad 初始化标题、共享菜单、store 绑定,读取 category_id/brand_id 并加载数据。
- loadData 调用 product 接口,支持按分类、品牌、排序、分页查询;concat=true 实现追加加载。
- 分类与排序
- 左侧分类树点击切换分类;顶部排序项切换 by/sort,重置页码并重新加载。
- 列表渲染
- 商品卡片包含缩略图、标题、价格(现价/促销标签/原价提示)、购物车图标入口。
- 分页与高度
- onReachBottom 触发下一页;getTreeHeight 计算左侧树高度以适配不同屏幕。
sequenceDiagram
participant U as "用户"
participant PC as "商品列表页<br/>product_category.ts"
participant H as "HTTP 层<br/>http.ts"
participant A as "后端控制器<br/>ProductController.php"
U->>PC : 打开列表/切换分类/排序
PC->>H : GET /product?category_id=&brand_id=&by=&sort=&page=
H->>A : 发起网络请求
A-->>H : 返回 {product_list, sort_list, cate_info, ...}
H-->>PC : 解析后返回 data
PC->>PC : setData({product_list, loadpage=false, ...})
PC-->>U : 渲染列表/排序/分类
HTTP 层与错误处理(http.ts)
- 信封解析
- 将后端返回的 {code,message,data,errors,request_id} 标准化,code==='OK' 视为成功,否则构造 ApiError。
- 缓存与去重
- GET 请求支持内存缓存与 TTL;相同 GET 在飞行中复用 Promise,减少重复请求。
- 拦截器
- onRequest/onSuccess/onError 可注册全局钩子,便于统一鉴权、埋点、异常处理。
- 调试
- 开发环境自动附加 request_id 到错误信息,必要时弹出服务端异常堆栈并支持复制。
后端 API(ProductController.php)
- 商品列表 index
- 接收 category_id、brand_id、by、sort、page 等参数,构建商品列表数据与分类树、排序选项。
- 商品详情 show
- 根据 id/slug/category_slug 解析商品 ID,组装商品详情、定义字段、功能开关与优惠券列表。
- 属性列表 attributeList
- 根据商品 ID 与已选属性组合,返回可选属性、价格、盒装信息等。
依赖关系分析
- 页面与 HTTP 层解耦:product 与 product_category 仅依赖 http.ts 的 get/post,不关心底层实现。
- 后端控制器依赖服务与模块:ProductController 通过 FrontProductService 与 Module(如 coupon、attribute)聚合数据。
- 路由与参数:小程序侧通过 route('...') 生成 URL,后端通过 RouteId 解析多种 ID 形式。
graph LR
P["product.ts"] --> H["http.ts"]
PC["product_category.ts"] --> H
H --> C["ProductController.php"]
C --> S["FrontProductService"]
C --> M["Module(coupon/attribute)"]
性能与响应式优化
- 图片优化
- 使用 widthFix 模式与 imageLoad 动态计算高度,避免重排;大图建议在服务端生成多尺寸缩略图。
- 列表与分页
- 列表采用分页加载,onReachBottom 延迟 1s 再请求,降低瞬时压力;合理设置 pageSize(默认 6)。
- 请求去重与缓存
- 利用 http.ts 的 dedupe 与 cache/ttl 机制,对频繁 GET 进行复用与缓存,减少网络开销。
- 响应式布局
- 通过媒体查询与动态高度计算,适配不同屏幕;左侧分类树高度基于窗口与顶部区域动态计算。
- 渲染优化
- 使用 wx:key 提升列表渲染性能;避免在 setData 中传入过大对象,按需更新字段。
故障排查指南
- 常见错误
- 网络异常:http.ts 会抛出 NETWORK_ERROR,检查网络与域名配置。
- 业务错误:code !== 'OK',查看 message/errors 定位问题。
- 未登录:部分操作需先 ensureLogin,确保 token 有效。
- 调试技巧
- 启用开发环境后,错误消息附带 request_id 尾缀,便于与服务端日志对照。
- 必要时可弹出服务端异常堆栈并复制,快速定位后端问题。
- 常见问题定位
- 商品详情空白:检查 product.show 是否返回有效 product 与 defined。
- 价格显示异常:确认 sale_price.format/name/type 字段存在且正确。
- 属性不更新:检查 attribute_data_box 与 attributeList 的参数是否正确。
结论
DouPHP 小程序的商品展示组件通过清晰的页面分层、统一的 HTTP 封装与稳定的后端 API,实现了商品列表、详情与分类的高效展示。借助图片自适应、分页加载、请求去重与缓存等策略,兼顾了用户体验与性能。开发者可在此基础上扩展更多业务特性,如更多筛选维度、评价互动、营销活动等。
附录:API 数据契约与使用示例
- 商品列表接口(product)
- 请求参数:category_id、brand_id、by、sort、page
- 返回关键字段:product_list、sort_list、cate_info、category_id、title、product_category
- 使用示例:product_category.ts 中 loadData 调用 route('product') 并处理分页与排序
- 商品详情接口(product.show)
- 请求参数:id/slug/category_slug
- 返回关键字段:product(含 title、image、gallery_list、sale_price、price_format/price、point 等)、defined、coupon_list、open
- 使用示例:product.ts 中 onLoad 调用 route('product.show') 并渲染
- 属性列表接口(product.attribute_list)
- 请求参数:id、mode、attribute_data(JSON 字符串)
- 返回关键字段:attribute_list、box(含 sale_price、price、point 等)
- 使用示例:product.ts 中 attributeList 根据属性选择刷新