系列选型与比较
先定真实差异属性,再实现筛选、结果与型号比较。
真实属性筛选与空结果
用 collection.filters 的实际选项、参数名和结果数生成表单,保持已选状态。先让提交与清除可靠,再增强为手机抽屉。
数据与依赖
- 真实配置的 list/boolean 筛选。
- 价格区间需要单独使用对应 min/max 字段。
交互逻辑
- 无结果且未选中的值禁用。
- 已选的零结果值仍可取消,排序值保留。
示例代码 · snippets/ww-filters.liquid
<form action="{{ collection.url }}" method="get">
{% for filter in collection.filters %}
{% if filter.type == 'list' or filter.type == 'boolean' %}
<fieldset>
<legend>{{ filter.label | escape }}</legend>
{% for value in filter.values %}
<label>
<input type="checkbox" name="{{ value.param_name }}" value="{{ value.value | escape }}"
{% if value.active %}checked{% endif %}
{% if value.count == 0 and value.active == false %}disabled{% endif %}>
{{ value.label | escape }} ({{ value.count }})
</label>
{% endfor %}
</fieldset>
{% endif %}
{% endfor %}
<input type="hidden" name="sort_by" value="{{ collection.sort_by | default: collection.default_sort_by }}">
<button type="submit">Apply filters</button>
<a href="{{ collection.url | escape }}">Clear all filters</a>
</form>
<p>{{ collection.products_count }} products</p>
验收检查
- 核有结果、无结果、组合与重置。
- 刷新后核参数、选择与结果一致。
片段不处理价格区间;分面 URL 的抓取策略另行确认,不能只靠前端隐藏参数。
商品网格、排序与分页
保留系列导语,把筛选后的商品交给统一卡片渲染;原生分页负责可达结果。排序提交应保留已选筛选,不能只重排当前屏幕的商品。
数据与依赖
- collection.products 及产品卡片依赖。
- 排序来自 collection.sort_options,与当前参数一起提交。
交互逻辑
- 没有结果时给出调整入口。
- 翻页后显示对应商品和可读页码。
示例代码 · snippets/ww-collection-grid.liquid
<h1>{{ collection.title | escape }}</h1>
<div>{{ collection.description }}</div>
{% paginate collection.products by 24 %}
<ul class="ww-product-grid">
{% for product in collection.products %}
<li>{% render 'ww-product-card', product: product %}</li>
{% else %}
<li>No matching products. Change or clear the filters.</li>
{% endfor %}
</ul>
{{ paginate | default_pagination }}
{% endpaginate %}
示例代码 · snippets/ww-product-card.liquid
{% assign card_product = product %}
{% assign card_variant = card_product.selected_or_first_available_variant %}
{% assign card_form_id = 'CardProduct-' | append: section.id | append: '-' | append: card_product.id %}
<article>
<a href="{{ card_product.url | escape }}">
{% if card_product.featured_image %}
{{ card_product.featured_image | image_url: width: 640 | image_tag: widths: '320, 480, 640', sizes: '(max-width: 749px) 45vw, 25vw', loading: 'lazy' }}
{% endif %}
<h3>{{ card_product.title | escape }}</h3>
</a>
<p>{{ card_product.metafields.custom.key_spec.value | escape }}</p>
<p>{{ card_variant.price | money_with_currency }}</p>
{% if card_product.has_only_default_variant and card_variant.available %}
{% form 'product', card_product, id: card_form_id %}
<input type="hidden" name="id" value="{{ card_variant.id }}">
<button type="submit">Add to cart</button>
{% endform %}
{% else %}
<a href="{{ card_product.url | escape }}">Choose options and check availability</a>
{% endif %}
</article>
示例代码 · assets/ww-module-layout.css
.ww-product-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 1.25rem;
list-style: none;
padding: 0;
}
.ww-product-grid img { width: 100%; height: auto; }
.ww-product-grid h3 { overflow-wrap: anywhere; }
.ww-table-scroll { max-width: 100%; overflow-x: auto; }
.ww-table-scroll table { border-collapse: collapse; min-width: 30rem; }
.ww-table-scroll th, .ww-table-scroll td { padding: .75rem; text-align: start; }
@media (max-width: 749px) {
.ww-product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .75rem; }
}
验收检查
- 从第一页进入最后一页再返回。
- 核排序/筛选组合和卡片价格。
示例依赖 ww-product-card 片段,样式应接现有主题网格;排序控件与筛选表单一起整合。
型号差异与 HTML 对比表
按顾客的用途与适配问题挑选比较维度,以同单位和测试条件展示。参数使用真实文字,型号链接回具体商品。
数据与依赖
- collection.custom.comparison_products:list.product_reference。
- 商品 custom.key_spec 与正式规格资料一致。
交互逻辑
- 缺少资料显示未提供,不自行补零。
- 手机表格可聚焦横向阅读,保留列标题。
示例代码 · snippets/ww-comparison.liquid
{% assign models = collection.metafields.custom.comparison_products.value %}
{% if models != blank %}
<div class="ww-table-scroll" role="region" aria-label="Model comparison" tabindex="0">
<table>
<caption>Compare the models in this collection</caption>
<thead><tr><th scope="col">Model</th><th scope="col">Use and key specification</th></tr></thead>
<tbody>
{% for model in models %}
<tr>
<th scope="row"><a href="{{ model.url | escape }}">{{ model.title | escape }}</a></th>
<td>{{ model.metafields.custom.key_spec.value | default: 'Not supplied' | escape }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
示例代码 · assets/ww-module-layout.css
.ww-product-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 1.25rem;
list-style: none;
padding: 0;
}
.ww-product-grid img { width: 100%; height: auto; }
.ww-product-grid h3 { overflow-wrap: anywhere; }
.ww-table-scroll { max-width: 100%; overflow-x: auto; }
.ww-table-scroll table { border-collapse: collapse; min-width: 30rem; }
.ww-table-scroll th, .ww-table-scroll td { padding: .75rem; text-align: start; }
@media (max-width: 749px) {
.ww-product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .75rem; }
}
验收检查
- 用一个实际选型问题走到型号。
- 核相同单位、条件及商品链接。
示例只有一项比较维度;需要更多规格时从同一字段字典扩展列。
先理解,再整合,最后验证
- 选择模块,确认数据和输入输出。
- 将片段接入当前主题或框架。
- 用真实变体、市场和失败恢复场景验收。
示例按 Shopify Online Store 2.0 主题编写;Headless 使用单独的数据与版本边界。代码片段需接实际字段、主题和语言文件。
架构参考
示例由 WESWOO 编写,结合 Shopify 官方文档和固定版本的仓库参考。采用仓库代码时应保留适用许可。
Shopify/dawn · 许可commit 3e9ee2281dc4 · Shopify 集成主题的限定许可;参考架构,不复制仓库实现。
Shopify/hydrogen · 许可commit 9e358a2462ba · MIT;采用实质代码时保留版权与许可。
依据核对 2026-11-12