结账页切换配送方式、使用优惠码或修改地址后,总价仍显示旧金额,刷新页面才正确。问题可能在后端 Quote 没有重算,也可能接口已经返回新 totals,但 Knockout 组件没有更新。先区分数据与显示,才能避免在错误层修补。
以接口响应判断后端是否正确
在 Network 中查看 estimate-shipping-methods、shipping-information、payment-information 或 totals-information 请求。响应中的 subtotal、shipping、tax、discount 和 grand_total 已更新,说明后端计算正确;响应仍旧则查 Quote、地址和 total collector。
不要只看页面文本。一步结账扩展可能显示自己的汇总,却仍发送核心接口。
Knockout totals 是 observable 数据
核心 checkout 使用 quote totals observable。自定义组件如果在 initialize 时读取一次普通值,后续不会响应变化。正确方式是订阅 totals 或使用计算属性,并处理 segment 暂时不存在的状态。
define(['Magento_Checkout/js/model/quote'], function (quote) {
'use strict';
return function () {
var totals = quote.getTotals()();
return totals ? totals.grand_total : 0;
};
});
示例只说明数据来源,真实组件应避免在模板每次渲染中创建重复订阅。
自定义 Total 必须前后端名称一致
PHP Total Collector 的 code、REST totals segment、jsLayout 组件与模板取值必须对应。后端返回 custom_fee,前端却查 custom-fee,组件就会一直显示空。排序值还会决定它在税、折扣和 grand total 周围的位置。
Promise 链未完成会阻止下一次更新
配送或支付模块覆盖 action 后,如果没有 return 原 Promise,调用方无法等待完成;失败分支没有 reject/always,也可能让 loader 和 totals 更新卡住。检查 mixin 是否保留函数返回值,并从 Console 第一条异常开始修复。
竞争请求会让旧响应覆盖新响应
客户快速切换地址或配送方式时,多个 totals 请求并发。较早请求较晚返回,就可能覆盖新选择。自定义组件应取消过期请求或根据当前状态忽略旧响应,不能简单在每次键盘输入都发完整 totals。
缓存不能缓存客户专属 totals
结账数据属于 Quote 私有状态。CDN、Service Worker 或错误的 Ajax 缓存规则如果缓存 totals API,会让不同请求得到旧数据。确认接口响应使用合适的私有/不缓存策略。
修复后按顺序测试地址、运费、优惠码、支付方式、数量和货币切换,观察每一步接口与页面金额一致。还要验证下单后的 Order、Invoice 与页面最终金额相同,不能只让 UI 看起来更新。

