Skip to main content
事件让你可以在购物车中发生某事时运行代码。它们位于 window.aftersell.cart.events 下。 订阅是一个设置类调用,所以可以安全地放在脚本顶部,无需等待 ready()

可用事件

订阅

events.on(event, handler) 注册一个处理函数并返回一个用于取消订阅的函数
  • events.once(event, handler):触发一次后自行取消订阅。
  • events.off(event, handler):移除特定的处理函数。
抛出错误的处理函数会被隔离并记录到控制台;其他处理函数仍会运行。

两条规则

几乎所有事件相关的 bug 都可以追溯到这两条之一。

不要在没有防护的情况下从 cart_updated 更改购物车

cart_updated 处理函数内部更改购物车会再次触发 cart_updated。如果那个处理函数又更改了购物车,你就有了一个无限循环。购物者会看着购物车反复抖动,而页面则疯狂请求 Shopify。
**永远不要从 cart_updatedcart_loaded 中无条件地调用操作。**用一个针对你即将创建的状态的检查来防护它,使第二次执行什么都不做。
购物车确实给了你一道安全网:产生完全相同购物车的更新不会发出任何事件,所以没有任何变化的重新获取不会重启循环。这能保护你免受意外的空操作循环。但它不能保护你免受每次都真正更改购物车的处理函数的影响。

将载荷视为只读

同一事件的所有处理函数接收的是同一个对象。修改它会改变你之后的处理函数看到的内容,包括商店中其他应用的处理函数。
要真正更改购物车,使用操作。要更改行的渲染方式,使用 registerLineTransform

cart_loaded

在购物车于页面上首次加载时触发一次。载荷是完整的购物车对象
**适用场景:**任何需要针对购物车初始状态运行的逻辑,例如协调免费赠品、初始化小组件,或在页面加载时向分析工具上报购物车内容。 **cart_loaded 会向迟来的订阅者重放。**如果你在购物车已经加载后才订阅,你的处理函数会立即以当前购物车被调用。订阅顺序从不重要,所以你不必担心你的脚本是否抢在了购物车之前。
既要在页面加载时正确、又要在之后每次变化时正确的逻辑,应该用同一个函数同时订阅 cart_loadedcart_updated。这是”让 X 与购物车保持同步”的标准模式。

cart_updated

在首次加载之后,购物车内容每次变化时触发,无论变化来自抽屉、你自己的操作、主题还是其他应用。载荷是完整的购物车对象
**适用场景:**让购物车之外的东西保持同步,例如自定义总额、进度条、页眉徽章,或每次变化时的分析事件。 产生完全相同购物车的更新不会发出任何事件。重新打开抽屉、切换回标签页,或返回相同内容的重新获取都不会触发它。
在这里调用操作之前,请重读两条规则

item_added

在购物车中出现新的一行时触发。载荷是 { item },其中 item购物车行
**适用场景:**在第三方分析工具中追踪加入购物车。这是 SDK 最常见的用途。参阅追踪加入购物车 关于它的推导方式,有两点需要知道:
**数量变化不算添加。**购物车通过对而不是数量进行差异比较来判断添加和移除。购物者把某行从 1 增加到 3 会触发 cart_updated,而不是 item_added。如果你也需要捕获数量增加,请在 cart_updated 处理函数中与之前的状态进行比较。
它也不会为页面加载时已经在购物车中的商品触发;那些通过 cart_loaded 到达。一次性添加多个不同产品会为每一行触发一次该事件。

item_removed

在某行从购物车中消失时触发。载荷是 { item },即该行消失前一刻的样子,所以你仍然可以读取它的 keyvariantIdtitle
**适用场景:**撤销你在添加时做的事,例如清除标志、重新显示购物者拒绝过的优惠,或向分析工具上报移除。 item_added 有同样的注意事项:数量降低但未归零不算移除。

cart_opened 和 cart_closed

在抽屉打开和关闭时触发。没有载荷。
**适用场景:**浏览追踪、暂停抽屉后面的视频或轮播、切换页面上的类名。 两者都不会在页面初始加载时触发,只在实际打开或关闭时触发。

checkout

在购物者点击结账按钮时、浏览器跳转之前触发。没有载荷。
**适用场景:**结账意向追踪。
**你无法从这个处理函数中取消结账。**该事件是一个通知,而不是一道闸门;无论你的代码做什么,跳转都会发生。让处理函数保持快速和同步:await 或慢速网络调用可能在页面卸载前无法完成。任何需要可靠发送的内容请使用 navigator.sendBeacon

从 SDK 外部监听

每个事件也会作为 DOM CustomEventwindow 上派发,所以你可以在不接触 window.aftersell.cart 的情况下监听。这在主题文件、第三方应用或独立于购物车加载的脚本中很有用。 注意命名:总线使用 snake_case,DOM 事件在 aftersell:cart: 前缀后使用 kebab-case
载荷通过 event.detail 到达,与购物车对象一致。事件在 window 上派发,所以页面上任何位置的监听器都能收到。购物车渲染在 shadow root 中,但 shadow 边界从不在事件的传播路径中。每次派发都会克隆载荷,所以修改 event.detail 的监听器不会影响其他任何人,抛出错误的监听器也不会干扰 SDK。
**cart-loaded 不会在 DOM 上重放。**总线会向迟来的订阅者重放 cart_loaded,但那条路径绕过了 DOM 派发,所以在购物车已加载后注册的 window.addEventListener('aftersell:cart:cart-loaded') 永远不会触发。如果你的脚本加载顺序无法保证,请使用会重放的 window.aftersell.cart.events.on('cart_loaded', …),或者同时监听 aftersell:cart:cart-updated

Shopify 标准购物车事件

另外,购物车在每次更改购物车时都会在 document 上发布 Shopify 的标准购物车事件,这样主题代码和其他应用就可以像响应主题的变更一样响应 Aftersell 的变更:
载荷不在 event.detail 上。detail 只携带 { source: 'aftersell' }——购物车用来忽略自己的事件以避免循环的标签。上表中的所有内容都直接赋值到事件对象上,所以要读取 event.action,而不是 event.detail.action
每个事件还携带一个 promise,Aftersell 会在底层写入落定时将其 settle,符合 Shopify 的标准——await 它,不要去 resolve 它。这些事件在 document 上派发并会冒泡,所以 window 上的监听器也能收到。

后续阅读

  • 购物车对象:上述载荷的完整结构。
  • 操作:如何从处理函数中更改购物车。
  • Hooks:用于更改购物车的渲染方式,而不是响应它。
  • 使用案例:分析追踪、免费赠品和其他完整示例。