Skip to main content
自定义模板让你可以覆盖单个区块的渲染方式。购物车不再渲染区块的内置 UI,而是渲染你自己的 JSX,使用的仍是该区块通常会使用的相同数据。它是一项横切能力,而不是一个独立的区块:大多数区块都在其 Code 标签页中提供此功能。 本页介绍适用于所有区块的内容。若要了解特定区块提供给你的 props,请跳转到该区块自己的参考

自定义模板与自定义代码区块的区别

两者听起来相似,但作用不同:
  • 自定义模板用你自己的标记替换现有区块的渲染,并把该区块自身的数据交给你(Header 的标题和商品数量、Summary 的总额等等)。它不会添加任何新内容;它只是为一个区块重新设计样式。
  • **自定义代码**区块则是在购物车的任意位置添加一个新区块,内容为任意 HTML 或 React。
当内置区块基本符合需求,但你需要不同的布局或标记时,选择自定义模板。当你想添加内置区块未涵盖的内容时,选择自定义代码区块。

使用自定义模板

  1. 在编辑器中选择一个区块并打开其 Code 标签页。
  2. 编辑默认模板。自定义模板仅支持 JSX(HTML 或 JSX 的选择仅限于自定义代码区块)。
  3. 点击 Compile。编译会去除类型并转译 JSX,因此它能捕获语法错误。类型错误不会阻止编译——编辑器会在你输入时以内联方式标记它们,并提供可自动补全区块 props 的同款 IntelliSense。
  4. 启用模板,让购物车使用它替代内置渲染。
  5. Reset to default 可随时恢复该区块的原始模板。

用 AI 编写模板

Code 标签页包含一个 Copy AI prompt 按钮(✦ 魔杖图标)。点击它会将一份自包含的简报复制到剪贴板,你可以直接粘贴到 AI 对话中(Claude、ChatGPT 或类似工具)。 该提示词包含 AI 为该特定区块编写有效模板所需的一切:
  • 编译规则(单一表达式、无 export default、无导入)
  • 该区块接收的确切 props,与编辑器 IntelliSense 显示的一致
  • 编辑器强制执行的锁定函数签名
  • 区块特定规则(货币格式、需要接线的处理函数、无障碍要求)
  • 一个填空部分,供你粘贴当前模板并描述想要的改动
复制后,打开 AI 会话,粘贴提示词,填写底部的两个空白处(你当前的模板和想要的改动),然后发送。AI 会返回一个完整的模板,你可以将其粘贴回编辑器并编译。
请将你现有的模板粘贴到填空部分,而不要留空。AI 会以它为起点,这样你已经做过的所有自定义都会得到保留,而不会被默认模板取代。
提示词是针对每个区块定制的。Copy AI prompt 按钮只出现在支持自定义模板的区块上。
你的起点默认模板是该区块内置标记的可运行副本,所以你始终拥有一个正确、可渲染的参考来修改,而不是从空白页开始。任何时候想找回这个参考,就使用 Reset to default它并不总是逐字节一致。Header 的默认模板还会渲染 logoUrl,而内置标记没有为它安排位置,所以启用该模板正是让上传的页眉图片首次显示的方式。

你的模板替换了什么

模板会完全替换区块的渲染。你的 JSX 外面不会保留任何包装器,在开始删除内容之前,有些后果值得了解:
**Design 标签页是最容易让人措手不及的一项。**当自定义模板处于启用状态时,Design 标签页的字段会被禁用,“Design” 标题旁会出现警告图标。将鼠标悬停在图标上可查看原因。请改为从模板中为区块设置样式,使用内联样式或你自己的 CSS。关闭自定义模板后,这些字段会立即重新启用。
你保留的内容:区块在购物车中的位置、其可见性开关、其设置(这些设置仍会作为你接收的 props 的数据来源)、购物车的自定义 CSS 面板,以及内置的加载骨架屏 最后一项常让人意外。区块会在到达你的模板之前检查购物车是否仍在加载,所以内置骨架屏会在加载期间渲染,而你的模板只在购物车就绪后运行。你不必构建加载状态。

模板内部可用的内容

你的模板是一个单一的函数组件。它从 TSX 编译而来,所以允许使用类型注解,并在编译时被去除。这就是默认模板带有类型注解的原因:
签名行和结束花括号是锁定的——编辑器不允许你编辑它们中的任何一个,悬停时会显示 “Locked — this line can’t be edited.”。你在它们之间编写函数主体。只有 Reset to default 能替换它们。 其他要点:
  • 你有五个 hooks 可用:useStateuseEffectuseMemouseRefuseCallback。外加 Fragment,用于 <>…</>
  • **没有导入。**你不能 import 任何东西,作用域内也没有 React 对象,所以没有 React.useReducer,也没有 React.Children。如果某个 hook 不在上面的列表中,它就不可用。
  • **props 是只读的。**修改 prop 不会有任何用处。要更改购物车,请使用区块提供的处理函数 props(onCloseincrementselectPlan 等),而不要直接写入 props。
  • 可以访问 window,所以当区块的 props 无法满足需求时,模板可以通过 window.aftersell.cart 调用 Cart SDK

所有区块通用的约定

有三条规则处处适用,了解它们能消除大部分猜测:
  • ***Html props 是已消毒的富文本。**用 dangerouslySetInnerHTML 渲染它们。它们已经过购物车的消毒器处理,{{total_price}} 之类的商家令牌也已被解析。
  • **以 string 形式到达的价格已经按商店的货币格式格式化好了。**以 number 形式的价格以分为单位。每个区块只会给你其中一种,各区块的表格会说明是哪一种。
  • **在模板内部 isLoading 始终为 false。**区块会渲染其内置骨架屏,并且只在购物车加载完成后才调用你的模板,所以传入这个 prop 是为了完整性,而不是让你基于它做分支。
少数区块在某些状态下完全不渲染任何内容,所以你的模板永远不会收到空数据。Rewards 模板永远不会看到空的 milestones,Subscription upgrade 模板永远不会看到为 null 的 view。每个区块的参考都会注明适用之处,这样你就可以跳过空状态分支。

为自定义模板设置样式

你的起点默认模板带有该区块的类名。如何为你的修改设置样式,取决于你离这个起点走了多远。

两个类名家族

默认模板中的每个元素都带有一对类名,它们的作用截然不同: 所以 cart-internal-header__title 是让标题看起来像内置标题的原因,而 cart-external-header__title 才是当你想改变其外观时应该抓取的把手。

小改动:保留两个类名

如果你只是在现有结构内重新排序元素、重新命名标签或添加内容,请不要动这些类名。你可以免费保留内置外观,并通过针对 cart-external-* 挂钩的自定义 CSS 重新设置样式。

重构:去掉两个类名

一旦你要改变 DOM 结构而不只是微调,就把两个家族都从你的标记上移除,改用你自己的类名。每个家族都有各自的移除理由。 **去掉 cart-internal-* 是因为内置 CSS 是为内置 DOM 编写的。**在重构后的标记上保留这些类,你就会继承一些假设了你已不再拥有的元素的布局规则:期望不同子元素的 flex 容器、针对已移动元素的间距、相对于已删除元素的定位。这通常表现为你自己的 CSS “不起作用”,实际上是内置规则赢了。
**去掉 cart-external-* 是因为它是共享名称,不属于你。**这些类名在内置标记上有特定含义,而你的自定义 CSS 是为整个购物车编写一次的。如果重构后的模板重用它们,你写的任何规则都会同时作用于你的结构和内置结构。在你关闭自定义模板的那一刻就会出问题:区块恢复为内置标记,而你的 CSS 仍然指向它,现在为一个它从未针对过的 DOM 设置样式。使用你自己的前缀能让两者干净地分离,这样关闭模板就是一次干净的还原。
为你构建的内容设置样式有两种方式:

方式 1:你自己的类名加自定义 CSS

最适合需要维护或复用的内容。给你的类加一个不会与他人冲突的前缀,通常是你的商店或品牌名称:
然后在购物车编辑器中,在左侧面板选择 Cart settings,并在右侧打开 Custom CSS 标签页:
前缀比看起来更重要。没有前缀的话,像 .header.title 这样的类就有可能与购物车自身的类、其他应用的模板或未来的区块发生冲突。

方式 2:内联样式

无需在 CSS 面板之间来回切换,所有内容都在一处:
适合布局脚手架和一次性需求。它的局限也是常见的那些:没有 :hover 或其他伪类,没有媒体查询,也无法跨区块复用。一旦你需要其中任何一项,就改用方式 1。

选择一种方式

购物车渲染在 shadow root 中,所以你主题的样式表无法触及其内部。自定义模板的样式必须来自购物车自己的 Custom CSS 面板或内联样式,而不是来自你的主题。参阅自定义 CSS

模板失败时

损坏的模板永远不会破坏购物车。该区块会渲染空白,周围的一切照常工作,这很安全但容易被忽视:症状就是你的区块位置出现一片空白。 由于区块会静默消失而不是明显报错,发布前请务必在预览中检查模板。如果某个区块不见了,先打开浏览器控制台。 有两点值得防范,因为假设相反情况的模板都会崩溃:
  • **可为 null 的 props。**许多 props 在正常情况下就是 null(没有 logo 时的 logoUrl、没有图片时的 imageUrl、单变体产品上的 variantTitle)。使用前请先检查。
  • 可能为空的数组。discountTagsdiscountCodes 大多数时候都是 []

限制

  • **自定义模板是显示层面的覆盖。**要对购物车运行逻辑(订阅事件、添加商品、响应变化),请使用自定义脚本Cart SDK
  • **几乎所有区块都支持自定义模板。**例外是承载 Shopify 自有支付按钮的 Express payments 区块,以及 Cart items 容器本身,不过其中的 Product 行支持自定义模板。
  • **模板不能改变区块的根本功能。**它改变的是区块数据的呈现方式,而不是数据或其背后的行为。

每个区块的 props

每个区块传递各自的数据。完整的 prop 表格(含类型和实际示例)位于对应区块的页面: 自定义代码区块是唯一添加标记而非替换区块渲染的界面,所以它的 props 有所不同:整个购物车,外加一个加入购物车操作。参阅自定义代码区块 → Props