Dawn主题产品列表中颜色选框重复显示问题求助
问题描述
我在Dawn主题的产品主页区块里集成了产品目录,需要展示颜色和尺寸的单选按钮,于是引入了主题自带的product-variant-picker代码片段。为了让颜色按钮显示对应的实际颜色,我创建了自定义元字段(metafield)来存储颜色值。
现在遇到一个视觉问题:当一个颜色对应多个尺寸(即同颜色存在多个变体)时,颜色单选按钮会重复显示相同的颜色,虽然添加购物车功能正常,但界面上的颜色选项出现了重复。比如一款产品有4种颜色、2个尺寸,共8个变体,按预期应该显示4个颜色按钮,但实际渲染后前两个是同一种颜色,接下来两个是另一种颜色——本质是同颜色的多变体导致元字段输出时匹配错误。
用到的关键代码
1. product-variant-picker 代码片段
{%- unless product.has_only_default_variant -%} <variant-radios id="variant-radios-{{ section.id }}" class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {% if update_url == false %} data-update-url="false" {% endif %} > {%- for option in product.options_with_values -%} <fieldset class="js product-form__input"> {% render 'custom-product-variant-options', product: product, option: option %} </fieldset> {%- endfor -%} <script type="application/json"> {{ product.variants | json }} </script> </variant-radios> {%- endunless -%}
2. custom-product-variant-options 代码片段
{%- liquid assign variants_available_arr = product.variants | map: 'available' assign variants_option1_arr = product.variants | map: 'option1' assign variants_option2_arr = product.variants | map: 'option2' assign variants_option3_arr = product.variants | map: 'option3' assign product_form_id = 'product-form-' | append: section.id -%} {%- for value in option.values -%} {%- liquid assign option_disabled = true for option1_name in variants_option1_arr case option.position when 1 if variants_option1_arr[forloop.index0] == value and variants_available_arr[forloop.index0] assign option_disabled = false endif when 2 if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == value and variants_available_arr[forloop.index0] assign option_disabled = false endif when 3 if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == product.selected_or_first_available_variant.option2 and variants_option3_arr[forloop.index0] == value and variants_available_arr[forloop.index0] assign option_disabled = false endif endcase endfor -%} <input type="radio" id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}" name="{{ option.name }}" value="{{ value | escape }}" form="{{ product_form_id }}" {% if option.selected_value == value %} checked {% endif %} {% if option_disabled %} class="disabled" {% endif %} > {% if option.name == 'Color' %} <label class="color-swatch" style="background-color: {{ product.variants[forloop.index0].metafields.custom.color }}" for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}" > </label> {% else %} <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"> {{ value }} </label> {% endif %} {%- endfor -%}
问题根源
问题出在颜色标签的背景色获取逻辑:{{ product.variants[forloop.index0].metafields.custom.color }}。
这里的forloop.index0是遍历去重后的颜色选项列表(option.values)的索引,但product.variants数组是包含所有变体的(比如8个)。变体数组的排序通常是按尺寸分组的,比如红-小、红-大、蓝-小、蓝-大...,这就导致遍历颜色选项时,forloop.index0对应的变体可能和当前颜色不匹配——比如第二个颜色选项是“蓝”,但forloop.index0是1,对应到变体数组里的第二个变体还是“红-大”,所以颜色标签就错误地显示成红色了。
解决方案
我们需要修改颜色标签的背景色获取逻辑,不再依赖遍历索引匹配变体,而是找到第一个匹配当前颜色值的变体,再获取它的颜色元字段。
修改custom-product-variant-options中的颜色标签部分:
替换原来的代码:
{% if option.name == 'Color' %} <label class="color-swatch" style="background-color: {{ product.variants[forloop.index0].metafields.custom.color }}" for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}" > </label> {% else %}
为:
{% if option.name == 'Color' %} {%- comment -%} 筛选出当前颜色对应的第一个变体 {%- endcomment -%} {%- assign matching_variant = product.variants | where: option.name, value | first -%} {%- comment -%} 容错处理:如果元字段为空,设置默认灰色 {%- endcomment -%} {%- assign color_hex = matching_variant.metafields.custom.color | default: '#cccccc' -%} <label class="color-swatch" style="background-color: {{ color_hex }}" for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}" > </label> {% else %}
效果说明
product.variants | where: option.name, value:从所有变体中筛选出当前颜色选项对应的变体集合| first:取筛选结果中的第一个变体,确保每个颜色选项都能匹配到正确的颜色元字段,不会受变体排序影响- 新增的容错处理可以避免元字段为空时颜色按钮显示异常
这样修改后,不管同颜色有多少个尺寸变体,每个颜色选项都会显示对应正确的颜色,解决了重复/错误显示的问题。
备注:内容来源于stack exchange,提问作者Marling

