购物车摘要模块:从行项目到结账入口
购物车摘要模块让顾客在结账前核对“我要买什么、买多少、大概付多少、下一步去哪”。它同时服务购物车页与购物车抽屉(迷你购物车):两处是同一份购物车状态的两个入口,不是两套规则。
购物车摘要 = 行项目 × 平台金额 × 数量与备注操作 × 结账入口
先确定模块在完成什么任务
- 顾客问题:内容对不对?数量能不能改?优惠生效了吗?运费大概多少?现在能不能结账?
- 对象层级:购物车(cart)包含行项目(line),每行是一个变体加数量,可带销售计划与行属性;金额分行级与购物车级两层。
- 进入前已知:已加购的变体与数量、买家市场与币种、已应用的折扣、可能已填的备注。
本模块只负责“核对与提交”。选择变体与加购归购买区模块,优惠码输入与资格反馈归促销兑现,缺货与到货表达归库存状态与到货通知。
信息来源与输入
| 输入 | 来源 | 最低要求 |
|---|---|---|
| 行项目名称、变体选项、图片、链接 | 资源数据(商品与变体) | 名称与选项取自当前变体;已下架时说明而非静默删除 |
| 数量与规则 | 交易动作 + 变体数量规则 | 最小、最大与步长取自平台规则,不在前端写死 |
| 行价、划线价、行级折扣 | 平台状态 | 直接读取平台返回值,不用单价乘数量自算 |
| 小计、购物车级折扣、合计 | 平台状态 | 标明含义与币种;不是最终应付时不写“总计” |
| 运费与免运费门槛 | 平台状态 + 配送信息内容 | 数值来自配送规则的同一来源;无法核实时改为“结账时计算” |
| 支付方式提示 | 支付方式内容 | 只写结账实际启用的方式 |
| 备注、行属性 | 交易动作 | 说明用途;礼品信息不得当作已确认的服务 |
| 结账入口 | 平台链接 | 指向当前购物车,不缓存旧链接 |
金额、库存、可售性与折扣属于运行时数据,不得改写成静态文案,也不得在页面脚本里长期缓存。
金额只来自平台
前端不自算小计、折扣、运费、税费与合计。原因有三:折扣可能作用于行、购物车或配送;价格取决于市场与币种;税费与关税取决于地址与设置。自算结果只要与结账有一处不同,就会变成价格承诺问题。
平台对金额口径写得很具体,实现和文案都应对齐:
- Liquid 的
cart.items_subtotal_price是行级折扣之后、不含税费、购物车折扣与运费的金额;cart.total_price是折扣之后的金额;original_total_price是折扣之前。 - Storefront API 的
Cart.cost被描述为买家在结账时“预计”支付的费用,可能变化并以结账为准;CartCost带有subtotalAmountEstimated与totalAmountEstimated标志,totalTaxAmount、totalDutyAmount已标记弃用。 - 所有金额按买家的展示币种返回;Ajax 与 Liquid 以币种最小单位输出,格式化时必须用平台的金额格式与币种。
文案随之分级:能确认的写“小计”;受地址、税费或运费影响的写“预估”并说明“结账时确认”。本站的 Cart Cost 实验记录仍是未复现的草稿,不作证据;排查方法见金额排查。
状态与退化
| 状态 | 处理方式 |
|---|---|
| 空购物车 | 保留页面或抽屉,给出继续浏览入口;结账入口不可用并说明原因 |
| 一项与多项 | 结构不变;数量减到 0 即移除,要有明确提示;长列表在容器内滚动,摘要与结账入口保持可达 |
| 加载 | 更新期间保留原内容并禁用重复提交,金额区标记为更新中,不显示中间的错误数值 |
| 库存不足 | 就近说明“最多可买 N 件”或“暂时缺货”,不静默把数量改小;见下节 |
| 数量规则不满足 | 说明最小、最大或步长要求,并给出可用的数量 |
| 商品失效或变体下架 | 标出该行不可结账,提供移除与相似商品入口,不自动删除 |
| 过期 | 页面停留很久后,结账前重新读取购物车;平台购物车会过期 |
| 跨市场 | 市场或币种变化后整份重新读取,金额、运费与可用支付方式一并刷新 |
| 请求失败 | 保留顾客输入与原数量,提示可重试;结果未知时不宣称已更新 |
数量更新与库存不足
数量更新是交易动作,以平台返回为准:先请求,再用返回的购物车重绘,不先改界面再补请求。库存错误、数量规则错误与折扣警告是三类问题,分别处理,不合并成“更新失败”。页面、抽屉、吸底条同时存在时,任何一处更新后都要刷新所有可见入口。
可选展现与交互
- 购物车页:完整核对,有独立地址,适合刷新保持状态和结账前最终检查。
- 购物车抽屉:加购后就地核对并继续浏览,见Drawer;必须以购物车页作无 JavaScript 退化。
- 加购反馈:成功可用 Toast;库存不足这类需处理的错误留在原位。
- 固定结账入口:小屏可用Sticky Bar,不得遮挡焦点与错误信息。
抽屉里不放完整推荐列表、多步表单或长政策,这些回到页面。
页面组合中的位置
主要出现在购物车页与带抽屉入口的页面。顺序通常是:行项目 → 促销兑现 → 配送与免运费提示 → 摘要与结账入口。商品页、集合页不重复渲染金额摘要,只显示数量与入口。免运费门槛、时效与支付方式必须与配送信息、支付方式及结账实际显示一致,不一致时先修配置或文案,不保留矛盾版本。
无障碍与性能
- 数量控件有可见标签与明确名称,说明是哪一行、哪个商品;步进按钮的目标尺寸满足 WCAG 2.2 的最小要求。
- 移除、更新、优惠应用后的结果用状态消息告知。WCAG 2.2 的 4.1.3 Status Messages(AA)要求状态消息能在不获得焦点时被辅助技术呈现;3.3.1 Error Identification(A)要求以文字标明出错项并描述错误。
- 更新后焦点不能随被销毁的节点丢失,落到相邻行或标题。
- 只刷新受影响区域;Ajax 请求可用
sections参数在同一响应里取回分区 HTML。
映射到 Shopify
核验于 2026-09-29,均来自 shopify.dev 官方页面,只写页面所写。主题实现的行为链接到固定版本正文,不在此断言某主题文件。
| 机制 | 官方页面所写 |
|---|---|
| Ajax Cart API | 端点含 /cart.js(GET)、/cart/add.js、/cart/update.js、/cart/change.js、/cart/clear.js(POST);change.js 用 id(变体 ID 或行 key)或 line(从 1 起的序号)定位,quantity: 0 移除该行;clear.js 保留备注与属性 |
| 库存错误 | add.js 库存不足返回 422,说明文字为无法再添加该商品或该商品已售罄;页面写明 update.js 不校验已在购物车中的变体数量,可能超过可用库存;change.js 的库存错误行为该页未写,需实测 |
| 行拆分 | 同一变体但属性、价格或折扣不同会形成多行;行 key 会随属性或折扣变化而变,多行同变体时用 key 而不是变体 ID |
| 折扣码 | Ajax 页写明可通过 update.js 的 discount 参数应用折扣码(逗号分隔,空字符串移除);折扣展示指南则写手动折扣码只能在结账应用,不会出现在 cart 模板的 cart.discount_applications 中。两页口径需在目标店铺实测 |
| 分区渲染 | add、change、clear、update 可用 sections 参数带回最多五个分区的 HTML |
| 运费预估 | GET /cart/shipping_rates.json 返回预估运费,页面提示可能较慢且受限流,建议改用异步的 prepare_shipping_rates.json 与 async_shipping_rates.json |
| 备注与模板 | cart 模板用 name="note" 文本域与 attributes[名称] 输入,并需要 POST 到购物车地址的表单与 name="checkout" 的提交控件 |
| Storefront API | cartCreate 创建购物车并返回 checkoutUrl;cartLinesAdd 与 cartLinesUpdate 每次最多 250 行;变更返回 userErrors 与 warnings |
| 警告与错误 | 警告码含 MERCHANDISE_NOT_ENOUGH_STOCK、MERCHANDISE_OUT_OF_STOCK、PRODUCT_UNAVAILABLE_IN_BUYER_LOCATION 及多种 DISCOUNT_*;错误码含 INVALID_INCREMENT、MAXIMUM_EXCEEDED、MINIMUM_NOT_MET、CART_TOO_LARGE。警告不阻止变更完成 |
| 折扣码更新 | cartDiscountCodesUpdate 用新列表替换全部折扣码,应用后核对返回的 discountCodes |
| 上限与过期 | 官方无头购物车指南写明购物车最多 500 个行项目,未使用的购物车在创建后 30 天内过期;Cart 对象页写未记录过期期限,二者不一致,以指南为准并标注待复核 |
核对结果:免运费门槛进度在已读官方页面中未找到平台内置机制,帮助中心运费页也未写按订单金额设置免运费的细节。门槛数值必须由与运费规则相同的来源提供,不得在主题设置里另填一份长期不同步的数字。未核验:Ajax 页的 422 文案在各语言店铺的表现、change.js 库存行为、运费预估与结账的具体差异。
固定版本主题的页面与抽屉共享组件、数量更新与空车分支见 Horizon 购物车,加购提交见购买流程。
验证一次购物车摘要
- 空车进入,检查空状态与结账入口;加购一件后,页面与抽屉数量一致。
- 同一商品用两个变体加购,确认是两行,图片与选项正确。
- 数量增至超过库存,记录请求、响应与提示;再试数量规则的最大、最小与非步长值。
- 应用有效、无效与条件不足的折扣码,核对折扣项、小计与合计(见促销兑现)。
- 切换买家地区与币种,确认金额、运费与支付方式刷新。
- 填写备注后刷新,确认保留;删除最后一件,确认空状态与焦点。
- 用键盘与读屏软件操作数量与移除,检查状态消息是否被朗读;关闭 JavaScript,确认抽屉入口退化为购物车页链接。
记录变体、数量、请求、响应与最终结账金额。完整的端到端记录方式见购买与事件验证。
固定版本主题实现
- Dawn 购物车抽屉与加购通知、Horizon 购物车:两个主题的购物车页与抽屉。Dawn 全仓库搜索未找到购物车内折扣码输入与免运费进度。
- 页面级组成见 Shopify 购物车页配方。
固定基线为 Dawn v15.3.0 与 Horizon 4.2.0;结论限于这两个提交,均为静态源码分析,未运行验证。
待继续完善
- 在测试店铺实测
change.js库存不足的响应,以及折扣码经update.js的实际行为。 - 缺少免运费门槛与运费规则同步的可验证做法。
- 运费预估与结账实际金额的差异需要样本验证。
- 未做真实读屏与移动端测试。