Shopify自定义店铺页面开发:实现分步式商品选择与结算流程
Shopify分步式购物流程实现方案
需求说明
我需要在Shopify店铺中创建一个自定义页面,实现以下分步购物流程:
- 第一步:展示变体选项(蛋白质偏好、分量规格、每周餐量),用户完成选择后
- 第二步:自动筛选并展示符合条件的商品
- 第三步:用户选中心仪商品后,进入结算环节
目前已完成自定义页面的静态结构搭建,代码如下:
<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
相关产品推荐
相关产品推荐

