跳到主要内容

Checkout extension 参考

本页讲 Checkout Extension 的运行机制:extend 函数、它渲染的 HTML 模板,以及怎么隐藏结账页的原生模块。扩展点清单见扩展点,数据与事件接口见 CheckoutAPI 参考。开发流程见 创建一个结账扩展;实战场景见 Checkout extension 场景教程

扩展点(Extension Points)

扩展点决定自定义内容插入到页面的具体位置。在 extend()extensionPoint 字段中指定对应名称,内容即会渲染在该位置。

结账页和感谢页各有一组固定的扩展点,按所在的页面区域分组。其中一部分是动态扩展点:它们跟着数据走,每个商品行、每个物流方案、每个弹窗各渲染一次,名字里带着那一行的 id,要在运行时拼出来。

完整清单、每个扩展点所属的区域,以及可以配合隐藏的原生模块,见扩展点

隐藏原生模块(deleteTarget)

deleteTarget 用于隐藏结账页的原生模块,比如各区块标题、地址簿、步骤面包屑。

在扩展目录下新建 extension.json,与 shoplazza.extension.toml 同级:

text
extensions/
└── my-checkout/
├── shoplazza.extension.toml
├── extension.json # 你只需要写 deleteTarget
├── package.json
└── src/

extension.json

json
{ "deleteTarget": ["contactInformationHeader", "shippingAddressHeader"] }

让配置生效:

  1. 把 Shoplazza CLI 升级到 2.0.10 或更高版本。
  2. 重启 shoplazza app dev 预览,或执行 shoplazza app deploy 发布。shoplazza app dev 不监听 extension.json,每次改完该文件都要重启。
  3. 恢复显示:把数组清空成 "deleteTarget": [],再部署一次。
  4. CLI 会自动往 extension.json 回写 extensionIdversion。这两个字段保留即可,不用手写,也不要删。

可隐藏的模块

Target位置说明
header页头顶部店名 / logo 区
navigate页头步骤面包屑,如 Information、Shipping、Payment
loginOrLogout页头登录 / 退出链接
returnBtn页头返回链接,与提交按钮并列渲染
contactInformation联系信息整个联系信息模块
contactInformationHeader联系信息「Contact」标题
contactEmail联系信息邮箱输入框
contactPhone联系信息手机号输入框
emailOrPhone联系信息邮箱与手机号合并输入框,店铺配成二选一时使用
contactSubscribe联系信息订阅营销邮件的勾选项
shippingAddress地址整个收货地址模块
shippingAddressHeader地址「Shipping address」标题
shippingAddressBook地址地址簿,用于选择已存地址
securityIdentifier地址安全与隐私标识
addressCard地址已填信息卡片,出现在配送步和支付步
billingAddress地址支付步的账单地址模块
deliveryMethod配送与自提配送方式模块,用于切换快递和自提
deliveryMethodHeader配送与自提配送方式标题
shippingList配送与自提物流方案列表
shippingLinesTitle配送与自提物流方案列表标题
pickupInformation配送与自提自提信息模块
pickupInformationHeader配送与自提自提信息标题
pickupAddress配送与自提自提点地址列表
pickupAddressHeader配送与自提自提点地址标题
paymentHeader支付支付方式列表标题
payPalExpress支付PayPal 快捷支付按钮
infoSubmit提交按钮信息步的「继续到配送」
shippingSubmit提交按钮配送步的「继续到支付」
paymentSubmit提交按钮支付步的「提交订单」
orderSummary订单摘要整个订单摘要,桌面端在右栏,移动端在顶部
orderSummaryHeader订单摘要订单摘要标题,移动端可折叠
productList订单摘要商品行列表
ProductListCover订单摘要商品行缩略图
productListSkuProperties订单摘要商品行的自定义属性,properties 非空才渲染
priceList价格明细整个价格明细区
priceListSubTotal价格明细小计
priceListShippingTotal价格明细运费
priceListTaxTotal价格明细税费
priceListShippingTaxTotal价格明细运费税
priceListGiftCard价格明细礼品卡抵扣
totalPrice价格明细合计
reductions优惠与备注优惠码与礼品卡输入区
mobileCoupon优惠与备注移动端的优惠码输入框,桌面端隐藏
giftCardTag优惠与备注已应用的优惠码或礼品卡标签,带移除按钮
specialInstruction优惠与备注配送步的订单备注输入框
thankyouHeader感谢页结账完成页头部
thankyouContent感谢页结账完成页内容
thankyouFooter感谢页结账完成页底部
thankyouShippingInfo感谢页物流信息块,有物流的订单才展示
thankyouFailOrderStatus感谢页订单取消或失败时展示的失败信息
thankyouPageGiftCardAddress感谢页虚拟商品订单展示的账单地址与礼品卡信息
thankyouPagePickupAddress感谢页自提订单展示的自提地址

CheckoutAPI 参考

CheckoutAPI 是结账页平台挂在 window.CheckoutAPI 上的全局对象,结账页和感谢页都有。扩展通过它读取订单和顾客已经做出的选择、监听这些数据的变化,以及驱动结账页的部分界面。

它的方法按命名空间分组:addressbaseconfigcouponexceptionextensionorderpaymentpickupstepstoresummarytrackuserutils

全部命名空间、类型定义,以及调用之前要知道的几条规矩——对象什么时候才挂上、on*remove* 怎么配对、register* 为什么不是监听器——见 CheckoutAPI 参考

extend 函数与 HTML 模板

extend 函数

extend 是将内容注册到扩展点的核心函数,从 shoplazza-extension-ui 引入:

javascript
import { extend } from 'shoplazza-extension-ui';

extend({
extensionPoint: 'Checkout::Navigate::RenderBefore',
component: '<h1>Hello, Shoplazza!</h1>',
});
参数类型必填说明
extensionPointstring内容渲染在哪个扩展点,清单见扩展点
componentstringPromise<string>要渲染的 HTML。普通字符串可以单独使用;传 Promise<string> 需要同时设 type: 'spz'
type'spz'最小形式不传这个参数。设成 'spz' 会启用 LessJS 组件库和下面说的占位符替换
localeMapobject按语言分组的文案,用来替换 component 里的 ${i18n('key')} 占位符。只在 type'spz' 时生效
idstring扩展 id。传 __EXTENSION_ID__,CLI 构建时会把它替换成扩展名

不传 type 时,component 就是一段 HTML 字符串,原样渲染。这是上面那个最小形式,多数扩展只需要它。

设了 type: 'spz' 之后,SDK 在渲染前多做三件事:加载 LessJS 组件库、接受 Promise<string> 形式的 component,以及用 localeMap 替换 HTML 里的占位符:

javascript
import { extend } from 'shoplazza-extension-ui';

extend({
type: 'spz',
extensionPoint: 'Checkout::Navigate::RenderBefore',
component: Promise.resolve(
"<div>${i18n('greeting')} - ${i18n('promo.line')}</div>"
),
localeMap: {
'en-US': { greeting: 'Hello', promo: { line: 'Free returns within 30 days' } },
'zh-CN': { greeting: '你好', promo: { line: '30 天内免费退货' } },
},
id: __EXTENSION_ID__,
});
  • ${i18n(...)} 里的 key 必须带引号${i18n('greeting')} 会被替换,${i18n(greeting)} 渲染出来是 undefined
  • 嵌套 key 用点号打平,promo: { line: … } 要写成 ${i18n('promo.line')}
  • 用哪一份文案取决于顾客的完整语言标记,也就是 localeMap 每一项的 key。
  • HTML 写成普通引号字符串,不要写成模板字符串,否则 ${…} 会被 JavaScript 先求值,轮不到 SDK 替换。
  • 占位符 {EXTENSION_POINT} 会被替换成由扩展点名派生的 id,例如 Checkout::Summary::RenderBefore 对应 Checkout-Summary-RenderBefore-ID
注意

安全提示(XSS 风险): component直接渲染的 HTML 字符串不要把未转义的用户输入或外部 API 返回值拼接进去,否则会导致 XSS 注入。任何动态内容先做 HTML 转义,或改用 createElement / textContent 等 DOM API 构造。

多次调用同一扩展点: 同一个 extensionPoint 可以被多次 extend,内容按调用顺序追加渲染,而不是覆盖。

HTML 模板

对于内容较复杂的扩展,推荐将 HTML 拆分到独立文件中管理。脚手架默认生成以下文件结构:

src/index.html(可选,组装入口):

html
<div>
import './style.html'
import './content.html'
import './script.html'
</div>
备注

import './xxx.html' 不是 ES Module 语法。 它是 shoplazza-cli 在构建时识别的文本拼接指令:在打包阶段,CLI 会把 import './xxx.html' 这一行原地替换为 ./xxx.html 文件的内容(按出现顺序内联),而不是运行时动态加载。

  • 该语法只能写在 src/index.html 顶层作为组装入口;写在 <script> 内部或 JS 文件里都不会被识别。
  • 被 import 的 HTML 片段不应再写 import,避免递归。
  • 内容简单或需要动态生成 HTML 时,可以跳过模板文件,直接在 index.js 中拼接字符串传给 component

src/style.html(可选,样式):

html
<style>
.my-block {
padding: 12px;
background: #f5f5f5;
}
</style>

src/content.html(可选,页面内容):

html
<div class="my-block">
<h2>Hello, Shoplazza!</h2>
</div>

src/script.html(可选):脚手架占位,若要在 HTML 模板片段内编写脚本,直接使用普通 <script> 标签即可:

html
<script>
document.querySelector('.my-block').addEventListener('click', function() {
window.CheckoutAPI.step.goToHomePage();
});
</script>

也可以不使用 HTML 模板,直接在 index.js 中构造 HTML 字符串传入 component,适合内容简单或需要动态生成的场景。

结账页性能预算

结账页性能直接影响转化率,扩展 JS / CSS 应尽量精简:单个扩展 gzip 后建议 < 30KB,避免引入大型依赖;优先用 setTimeout / IntersectionObserver 等被动方式而不是高频轮询。