EN
Shopify 知识库 · 指南

Dawn 商品推荐:相关商品、搭配商品与空结果行为

基于 Dawn v15.3.0 源码,追踪 related-products 分区与 main-product 内置 complementary 搭配区块怎样请求推荐端点、渲染网格或分页滑块、处理空结果,并对照通用交叉销售、Carousel 与 Grid 契约列出差距。
历史资料
请结合文中的适用版本和来源阅读。

本文基于 Dawn v15.3.0,源码固定到 ecb06c3(核验于 2026-09-29)。结论限于此提交,不表示其他版本行为相同;本篇为静态源码分析,未完成店铺运行验证。Dawn 上游已发布 v16.0.0(2026-08-10,GitHub Releases 核对),本库 Dawn 正文统一以 v15.3.0 为基线,升级前需重新核对。

对应哪些通用模式

覆盖交叉销售与追加购买模块中「搭配」与「相关商品」两类推荐在 Dawn 商品页上的实现:相关商品用Grid,搭配商品用类似Carousel的分页滑块,单张商品卡是Cards。内容层的关系与依据规则见相关商品。升级、捆绑与追加购买不在本篇范围,见下文的未内置结论。商品页整体管线见 Dawn 架构,加购后的反馈见购物车篇。

入口与文件

文件职责 / 何时输出
sections/related-products.liquid独立分区:product-recommendations 容器、标题与商品网格;默认模板 product.json 把它放在商品页最后
sections/main-product.liquid(complementary 区块)complementary 区块(limit: 1,默认模板未包含):请求 intent=complementary,输出 aside 与分页滑块
assets/global.js(ProductRecommendations)product-recommendations 自定义元素:进入视口前加载、替换内容、搭配为空时自删
snippets/card-product.liquid两处共用的商品卡;搭配区块可开启快速加购
assets/component-complementary-products.css、assets/section-related-products.css、assets/component-slider.css搭配区块的样式;相关商品容器样式;滑块样式与减少动态设置
templates/product.json默认区段顺序:main、image-with-text、multicolumn、related-products

数据从哪来

  • 推荐结果:两处都用 routes.product_recommendations_url 加查询参数,由 ProductRecommendations 补上 &product_id=<当前商品>&section_id=<所在区段 id>。相关商品只带 limit(products_to_show),搭配带 limit(product_list_limit)与 intent=complementary。端点的参数、intent 默认值与返回,见交叉销售模块「映射到 Shopify」所引的官方页面,本篇未联网复核。
  • Liquid 对象:模板里判断 recommendations.performed and recommendations.products_count > 0,循环 recommendations.products。内容来自 JS 发起的请求:recommendations.performed 预期只在经推荐端点渲染时成立(见交叉销售模块所引官方页面,未复核),因此普通页面渲染里这一分支预期不输出内容;响应是带 section_id 的分区渲染,JS 只取其中的 product-recommendations 元素(依据 section_id 的约定推断,未抓包)。
  • 谁决定推荐哪些商品:主题不做任何选择,不筛选可售性,也不排除购物车内商品;区段里的说明文字让商家到 Search & Discovery 应用里管理。资格规则见交叉销售模块所引的帮助中心页面。
  • 编辑器设置:related-products:heading(默认「You may also like」)、heading_size、products_to_show(2 到 10,默认 4)、columns_desktop(1 到 6)、columns_mobile(1 或 2)、image_ratio、image_shape、show_secondary_image、show_vendor、show_rating、配色与边距。complementary:block_heading(默认「Pairs well with」)、make_collapsible_row、icon、product_list_limit(1 到 10,默认 10)、products_per_page(1 到 4,默认 3)、pagination_style(dots / counter / numbers,默认 counter)、image_ratio(portrait / square)、enable_quick_add(默认关)。

交互怎样运行

加载。 connectedCallback 建立 IntersectionObserver(rootMargin: '0px 0px 400px 0px'),元素接近视口 400px 时才请求,请求一次后停止观察。响应解析进临时 div,取 product-recommendations,innerHTML 非空就替换当前元素内容;响应里有 .grid__item 时加 product-recommendations--loaded 类,检出内的 CSS 没有引用这个类(检索该类名)。请求失败只 console.error,没有检查 response.ok,也没有用户可见提示。

相关商品。 输出 h2 标题与 ul[role="list"] 网格,每项是 card-product;不传 quick_add,所以卡片上没有快速加购。列数由类名 grid--N-col-desktop、grid--N-col-tablet-down 控制,没有滑动或分页,swipe_on_mobile 这类设置在此分区里不存在。

搭配商品。 按 products_per_page 把结果分成若干「页」,每页是一个 role="group" 的纵向卡片列表,外层是 slideshow-component。多于一页才输出上一页、下一页按钮与计数器(点、n / N 或数字)。开启 enable_quick_add 后卡片传 quick_add: 'standard':单变体且无数量规则时卡片内直接是 product-form,否则是「选择选项」按钮并打开快速加购弹窗,两条路径最终都进入常规的加购与购物车反馈。可折叠形态用 details 包裹,图标沿用折叠行的图标集合。

换商品时。 选项值指向另一个商品 URL(data-product-url 不同)时,主区域整体被替换,新的 product-recommendations 重新连接并重新请求;同商品内的变体切换不会触发推荐刷新。ProductRecommendations 不订阅 cartUpdate,加购后推荐区不会自动刷新。

空结果与失败时

情形相关商品搭配商品
没有结果标题与列表都不输出,容器保留(related-products 类与区段边距类仍在该元素上,实际留白未核验)this.remove():响应里没有 slideshow-component 且元素带 complementary-products 类时整个元素被移除
请求失败容器保持为空,仅控制台报错元素保留为空,仅控制台报错
无 JavaScript只有空容器只有空容器

与通用契约的一致与差距

通用要求(交叉销售、Carousel、Grid)Dawn 现状
零项隐藏整个模块,不用随机商品填补搭配已做(元素自删);相关商品只隐藏标题与列表,容器与边距类残留。主题本身不补随机商品
加载不阻塞主购买按钮,失败时安静隐藏基本做到:视口前置加载、失败只报控制台;但没有为容器预留高度,加载完成时的布局位移未核验
推荐依据可解释、标题与依据一致部分:标题是商家可改的固定文字,默认「You may also like」「Pairs well with」;每项没有理由字段,主题不知道结果来自手动还是自动
已在购物车、不可售、不兼容的商品不显示主题不做筛选,完全依赖平台端点;加购后不刷新,刚加入的搭配商品会继续留在列表,直到换页或刷新(静态可推,未复现)
限制数量,按类型分组数量有上限设置(相关 2 到 10,搭配 1 到 10);两类推荐是两个独立区块,没有「升级」「捆绑」类型
加购按钮名称写明商品、不预勾选快速加购按钮用 aria-labelledby 同时引用按钮与商品标题;没有任何预勾选控件;默认关闭快速加购
加购后所有购物车入口一致复用常规 product-form 与购物车反馈,见购物车篇
搭配放在购买区之后默认模板没有 complementary 区块;位置取决于商家在 main-product 内的区块顺序
Carousel:真实按钮名称、当前序号与总数已做:上一页、下一页是带 aria-label 的 button,默认计数器显示当前与总页数;只有一页时不输出控制
Carousel:不自动轮播、暂停控制搭配区块没有 data-autoplay,不自动轮播,也就没有暂停按钮
Carousel:不可见项不进入 Tab 顺序部分:setSlideVisibility 给非当前页加 aria-hidden="true"、tabindex="-1",但只处理其中的 a;页内的快速加购 button 未被处理(静态阅读,未验证)
Carousel:减少动态偏好部分:component-slider.css 在 prefers-reduced-motion 下把 .slider 的 scroll-behavior 设为 auto
Grid:DOM 顺序即阅读顺序,用列表语义已做:ul[role="list"] 与 li,按响应顺序输出
Grid:一项时退化为单列由 CSS 类控制,未逐项核验
状态变化不打断读屏推荐区加载没有 live region,也不播报;这符合「不反复播报」,但读屏用户没有加载提示

在固定提交的全仓库搜索中,搭配商品由 main-product 的 complementary 区块内置(intent=complementary);以下均未找到:升级或捆绑商品的展示、「经常一起购买」勾选式加购、最近浏览、购物车页或抽屉里的推荐区块(搜索词:bundle、upsell、cross-sell、cross_sell、bought together、frequently、recently viewed、recently_viewed;intent 在整个检出内仅有 main-product.liquid 一处命中;范围为检出内全部文件,含 locales 与 config)。购物车页模板 cart.json 的末尾是 featured-collection,不是推荐。这只说明此版本主题没有内置,不表示平台不能实现。

定制入口与风险

商家的入口见「编辑器设置」;推荐结果本身在 Search & Discovery 应用里管理,主题内无法改。开发者的耦合点:

  • ProductRecommendations 靠 data-url、data-product-id、data-section-id 与元素内的 .grid__item、slideshow-component 判断状态,改标记会破坏自删与 --loaded 逻辑。
  • 搭配请求使用 main-product 的区段 id,响应是整段商品区段的渲染,只取其中的推荐元素;给该区段增加重内容会放大这次请求。
  • 相关商品与搭配共用 card-product;卡片改动同时影响集合页、搜索与推荐。
  • ProductInfo 里有一个 relatedProducts 取值器,在固定提交内没有调用点(检索 relatedProducts),改推荐结构时不必为它兼容。
  • 想要推荐区随加购刷新或补上升级、捆绑,需要新增订阅与数据来源,主题内没有现成的扩展点。

建议的验证范围

本篇均未执行:

  1. 选一个有手动搭配、一个只有自动推荐、一个没有推荐的商品,核对两处区块的显示、隐藏与容器留白;观察加载前后是否有布局位移。
  2. 让推荐请求失败(离线或拦截),确认页面表现与控制台。
  3. 搭配区块设为多页、开启快速加购,键盘走完翻页、非当前页内的按钮是否仍可聚焦、加购到超过库存的反馈。
  4. 加购一个已被推荐的商品,确认推荐区是否仍显示它;再切换变体与换到组合商品,观察是否重新请求。
  5. 开启系统减少动态、关闭 JavaScript,核对滑块与空容器;用读屏软件听推荐区的标题与分页信息。

源码基线