在 Shopify 中设计售罄选项

Styling Sold Out Options in Shopify

我正在尝试将 css 添加到产品选项中,以便为用户提供哪些选项不可用(已售罄)的视觉指示。当产品只有一组选项值时,此方法有效,但我的产品有两个(“日期”和“时间”)。我大部分时间都在使用此功能,但是当我在日期之间切换时,可用的“时间”选项不会更新。非常感谢此处的任何帮助。

在我的 product-form.liquid 文件中,我有以下代码来添加 class 到已售罄的选项。也许我需要一些 js?

如果有帮助,我使用的是 Prestige 主题,页面位于此处:https://neetfield.co.uk/pizza

                {%- if option.name == "Time" and product.selected_or_first_available_variant.option1 == product.variants[forloop.index0].option1 -%}
                  {%- if product.variants[forloop.index0].available -%}
                    {%- assign opt_sold = false -%}
                  {%- else -%}
                    {%- assign opt_sold = true -%}
                  {%- endif -%}
                {%- else -%}
                  {%- assign opt_sold = false -%}
                {%- endif -%}

然后这用于添加 class 到售罄选项 {% if opt_sold %}opt-sold-out{% endif %}

这是我到达的地方的屏幕截图(现在在实时网站上被禁用,直到我在日期之间切换时让它工作):

第一页呈现(液体)

对于初始页面加载,您可以使用如下内容:

{%- liquid
  assign selected_option_1 = product.selected_or_first_available_variant.option1
  assign relevant_variants = product.variants | where: 'option1', selected_option_1
  assign available_timeslots = ''

  for variant in relevant_variants
    if variant.available
      assign available_timeslots = available_timeslots | append: ',' | append: variant.option2
    endif
  endfor

  assign available_timeslots = available_timeslots | remove_first: ',' | split: ','
-%}

此代码段遍历所有产品变体,其中 option1 等于当前所选变体的 option1 值(例如“6 月 4 日,星期六”)。对于每个变体,我们将检查其是否可用并将其推送到 available_timeslots 数组。

确保在遍历所有产品选项之前放置此代码段。

最后,使用此数组检查选项值是否可用:

{%- unless available_timeslots contains value -%}
  Disable option input
{%- endunless -%}

value基本上就是一个option.values的值。我相信您会在 product-form 的某处找到它 :)

用户互动后(JavaScript)

由于 Liquid 是一种 server-side 呈现的模板语言,您只能通过 client-side 上的 JavaScript 更新变体更改时的选项输入元素来实现此目的。 Shopify Prestige 主题对这种情况很有用 CustomEventvariant:changed

实施示例如下所示:

/**
 * Gets the option index that is different between `variant` in `previousVariant`.
 *
 * @param {object} variant
 * @param {object} previousVariant
 * @returns {1 | 2 | 3}
 */
const getChangedOptionIndex = (variant, previousVariant) => {
  let changedOptionIndex;

  for (let i = 0; i < variant.options.length; i++) {
    if (variant.options[i] !== previousVariant.options[i]) {
      changedOptionIndex = i;
      break;
    }
  }

  return changedOptionIndex;
};

/**
 * Find a variant via its options.
 *
 * @param {object[]} variants
 * @param {{ option1: string, option2: string }} options
 * @returns {object | undefined}
 */
const findVariantByOptions = (variants, { option1, option2 }) => {
  return variants.find((variant) => variant.option1 === option1 && variant.option2 === option2);
};

const { product } = JSON.parse(document.querySelector('script[data-product-json]').innerHTML);

document.addEventListener('variant:changed', (event) => {
  // We might need a sanity check here. For example, if the current variant is
  // "Saturday 4th June / 18:30" and you switch to "Saturday 11th June" the time option
  // "18:30" might not exist which would result in `event.detail` being `undefined`.
  // if (!event.detail.variant) {
  //
  // }

  const { variant, previousVariant } = event.detail;
  const changedOptionIndex = getChangedOptionIndex(variant, previousVariant);

  const optionInputEls = document.querySelectorAll('input[name^="option-"]');

  // Note: This approach won't work anymore if a product has 3 options
  optionInputEls.forEach((optionInputEl) => {
    const optionIndex = Number(optionInputEl.name.split('-')[1]);

    // Only check option inputs that are not of the same group as the changed option
    if (optionIndex !== changedOptionIndex) {
      const foundVariant = findVariantByOptions(product.variants, {
        [`option${changedOptionIndex + 1}`]: variant.options[changedOptionIndex],
        [`option${optionIndex + 1}`]: optionInputEl.value,
      });

      if (!foundVariant || !foundVariant.available) {
        optionInputEl.nextElementSibling.classList.add('opt-sold-out');
      } else {
        optionInputEl.nextElementSibling.classList.remove('opt-sold-out');
      }
    }
  });
});

请记住,您并没有真正禁用输入。它只是在视觉上表明它已被禁用。如果这对您来说不是问题,请忽略此评论。

请注意,这不处理以下情况:

  • 用户选择日期“A”
  • 用户选择时间“X”
  • 用户选择日期“B”(时间“X”不可用)

我猜选择日期的决定总是最先发生的,所以这应该不是一个需要担心的重要场景。