You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shopify自定义店铺页面开发:实现分步式商品选择与结算流程

Shopify分步式购物流程实现方案

需求说明

我需要在Shopify店铺中创建一个自定义页面,实现以下分步购物流程:

  1. 第一步:展示变体选项(蛋白质偏好、分量规格、每周餐量),用户完成选择后
  2. 第二步:自动筛选并展示符合条件的商品
  3. 第三步:用户选中心仪商品后,进入结算环节

目前已完成自定义页面的静态结构搭建,代码如下:

<form method="post" action="/cart/add">
    <section class="prtn_cstm_crt_pg">
        <!--====================== step forms content========================= -->
        <div class="step-content">
            <!-- ~~~~~~~~~~~~~STEP 01~~~~~~~~~~~~~~ -->
            <div class="cstm_crt_first-step">
                <div class="Step_bnner">
                    <h1 class="Step_bnner_heading">CREATE YOUR FIRST BOX</h1>
                    <p class="Step_bnner_subtitle">Choose from 15 healthy, resturant-quality meals each week</p>
                </div>
                <div class="first-step-inner">
                    <!-- Choose Meal -->
                    <div class="Choose-meal">
                        <h2 class="step_heading">1. CHOOSE YOUR PROTEIN PREFERENCE</h2>
                        <p class="step_para">Your preferences will help us show you the most relevant meals first. You
                            will still be able to view all meals.</p>
                        <div class="select_boxs_first">
                            <div class="select_box">
                                <input type="radio" id="Veg_and_nonveg_meal_radio" name="protien-preference"
                                    class="select_radio_input" value="Meat & Vegan">
                                <label class="selector-item_label" for="Veg_and_nonveg_meal_radio">
                                    <span class="select_box_title">Meat & Vegan</span>
                                </label>
                            </div>
                            <div class="select_box">
                                <input type="radio" id="meat_radio" name="protien-preference" class="select_radio_input"
                                    value="Meat Only">
                                <label class="selector-item_label" for="meat_radio">
                                    <span class="select_box_title">Meat Only</span>
                                </label>
                            </div>
                            <div class="select_box">
                                <input type="radio" id="vegan_radio" name="protien-preference"
                                    class="select_radio_input" value="Vegan Only">
                                <label class="selector-item_label" for="vegan_radio">
                                    <span class="select_box_title">Vegan Only</span>
                                </label>
                            </div>
                        </div>
                    </div>
                    <!-- Choose Meal End -->

                    <!-- Meal Quantity -->
                    <div class="Meal-Quantity">
                        <h2 class="step_heading">2. CHOOSE YOUR PORTION PREFERENCE</h2>
                        <div class="select_boxs_second">
                            <div class="select_box_with_price">
                                <div class="select_box">
                                    <input type="radio" id="Standard_meal_radio" name="Meal-Quantity"
                                        class="select_radio_input" value="Standard">
                                    <label class="selector-item_label" for="Standard_meal_radio">
                                        <span class="select_box_title">Standard</span>
                                    </label>
                                </div>
                            </div>
                            <div class="select_box_with_price">
                                <div class="select_box">
                                    <input type="radio" id="large_meal_radio" name="Meal-Quantity"
                                        class="select_radio_input" value="Large">
                                    <label class="selector-item_label" for="large_meal_radio">
                                        <span class="select_box_title">Large</span>
                                    </label>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!-- Meal Quantity -->

                    <!-- Meal Number -->
                    <div class="meal__number">
                        <h3 class="step_heading">3. SELECT MEALS PER WEEK</h3>
                        <div class="select_boxs_second">
                            <div class="select_box_with_price">
                                <div class="select_box">
                                    <input type="radio" id="six_meal_pr_wk" name="meal__number"
                                        class="select_radio_input" value="6">
                                    <label class="selector-item_label" for="six_meal_pr_wk">
                                        <span class="select_box_title">6</span>
                                    </label>
                                </div>
                                <div class="select_box_description">
                                    <!-- <span class="meal_price_by_number"><em>(£7.49)</em> £5.99/meal</span> -->
                                </div>
                            </div>
                            <div class="select_box_with_price">
                                <div class="select_box">
                                    <input type="radio" id="eight_meal_pr_wk" name="meal__number"
                                        class="select_radio_input" value="8">
                                    <label class="selector-item_label" for="eight_meal_pr_wk">
                                        <span class="select_box_title">8</span>
                                    </label>
                                </div>
                                <div class="select_box_description">
                                </div>
                            </div>
                            <div class="select_box_with_price">
                                <div class="select_box">
                                    <input type="radio" id="ten_meal_pr_wk" name="meal__number"
                                        class="select_radio_input" value="10">
                                    <label class="selector-item_label" for="ten_meal_pr_wk">
                                        <span class="select_box_title">10</span>
                                    </label>
                                </div>
                                <div class="select_box_description">
                                </div>
                            </div>
                            <div class="select_box_with_price">
                                <div class="select_box">
                                    <input type="radio" id="twelve_meal_pr_wk" name="meal__number"
                                        class="select_radio_input" value="12">
                                    <label class="selector-item_label" for="twelve_meal_pr_wk">
                                        <span class="select_box_title">12</span>
                                    </label>
                                </div>
                                <div class="select_box_description">
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!-- ~~~~~~~~~~~STEP 01 END~~~~~~~~~~~~ -->
        </div>
    </section>
    <div class="product">
        <div class="page-width">
            <div class="product-variant-details">
                <!-- The updated variant details will be displayed here -->
            </div>
        </div>
    </div>
    <button id="plan-submit-btn" type="submit" class="custom_cart_next_btn">SELECT PLAN</button>
</form>

实现步骤

1. 关联商品标签与筛选条件

先在Shopify后台给商品添加对应标签,确保标签和页面选项值一一对应:

  • 蛋白质偏好:meat-vegan、meat-only、vegan-only
  • 分量规格:standard-portion、large-portion
  • 每周餐量:6-meals、8-meals、10-meals、12-meals

2. 编写JavaScript实现筛选逻辑

在页面底部添加JS代码,监听单选框变化,实时筛选并渲染商品:

document.addEventListener('DOMContentLoaded', function() {
    // 获取核心元素
    const proteinRadios = document.querySelectorAll('input[name="protien-preference"]');
    const portionRadios = document.querySelectorAll('input[name="Meal-Quantity"]');
    const mealCountRadios = document.querySelectorAll('input[name="meal__number"]');
    const productContainer = document.querySelector('.product-variant-details');
    const submitBtn = document.getElementById('plan-submit-btn');

    // 动态获取Shopify商品数据(通过Liquid注入)
    const allProducts = [
        {% for product in collections.all.products %}
        {
            id: {{ product.id }},
            title: "{{ product.title | escape }}",
            tags: [{% for tag in product.tags %} "{{ tag }}" {% unless forloop.last %},{% endunless %}{% endfor %}],
            price: "{{ product.price | money }}",
            image: "{{ product.featured_image.src | img_url: 'medium' }}"
        }{% unless forloop.last %},{% endunless %}
        {% endfor %}
    ];

    // 筛选并渲染商品
    function renderFilteredProducts() {
        // 获取选中的选项值
        const selectedProtein = Array.from(proteinRadios).find(r => r.checked)?.value;
        const selectedPortion = Array.from(portionRadios).find(r => r.checked)?.value;
        const selectedMealCount = Array.from(mealCountRadios).find(r => r.checked)?.value;

        // 未完成所有选择时提示用户
        if (!selectedProtein || !selectedPortion || !selectedMealCount) {
            productContainer.innerHTML = '<p>请完成所有选项选择以查看商品</p>';
            submitBtn.disabled = true;
            return;
        }

        // 转换选项值为对应标签格式
        const proteinTag = selectedProtein.toLowerCase().replace(' & ', '-').replace(' ', '-');
        const portionTag = `${selectedPortion.toLowerCase()}-portion`;
        const mealCountTag = `${selectedMealCount}-meals`;

        // 筛选符合所有标签的商品
        const filteredProducts = allProducts.filter(product => 
            product.tags.includes(proteinTag) && 
            product.tags.includes(portionTag) && 
            product.tags.includes(mealCountTag)
        );

        // 渲染结果
        if (filteredProducts.length === 0) {
            productContainer.innerHTML = '<p>没有找到符合条件的商品</p>';
            submitBtn.disabled = true;
            return;
        }

        let productHtml = '';
        filteredProducts.forEach(product => {
            productHtml += `
                <div class="product-item" style="border:1px solid #eee; padding:1rem; margin:1rem 0;">
                    <img src="${product.image}" alt="${product.title}" style="width:100px; height:auto;">
                    <h4>${product.title}</h4>
                    <p>价格: ${product.price}</p>
                    <input type="radio" name="selected-product" value="${product.id}" id="product-${product.id}">
                    <label for="product-${product.id}">选择此套餐</label>
                </div>
            `;
        });
        productContainer.innerHTML = productHtml;
        submitBtn.disabled = false;
    }

    // 给所有单选框添加变化监听
    proteinRadios.forEach(radio => radio.addEventListener('change', renderFilteredProducts));
    portionRadios.forEach(radio => radio.addEventListener('change', renderFilteredProducts));
    mealCountRadios.forEach(radio => radio.addEventListener('change', renderFilteredProducts));

    // 初始化渲染
    renderFilteredProducts();

    // 处理表单提交逻辑
    submitBtn.addEventListener('click', function(e) {
        const selectedProduct = document.querySelector('input[name="selected-product"]:checked');
        if (!selectedProduct) {
            e.preventDefault();
            alert('请选择一个商品套餐');
            return;
        }
        // 添加Shopify购物车所需的商品ID参数
        const form = this.closest('form');
        const existingIdInput = form.querySelector('input[name="id"]');
        if (existingIdInput) existingIdInput.remove();
        form.insertAdjacentHTML('beforeend', `<input type="hidden" name="id" value="${selectedProduct.value}">`);
    });
});

3. 优化用户体验

  • 给选中的单选框添加高亮样式,明确用户选择
  • 提交按钮在未完成选择或未选商品时置灰,避免无效操作
  • 给商品展示区域添加布局样式,让商品排列更整齐

内容的提问来源于stack exchange,提问作者Rahul Vidhuri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 04:52:04