购物车对象详解
购物车对象包含了用户当前购物车中的所有商品信息、价格计算、运费、税费等。掌握购物车对象是构建完整电商体验的关键。
购物车基本信息
购物车状态
<!-- 购物车基本信息 -->
<div class="cart-summary" data-cart-count="{{ cart.item_count }}">
  {% if cart.item_count > 0 %}
    <h2>购物车 ({{ cart.item_count }} 件商品)</h2>
    
    <div class="cart-meta">
      <p><strong>商品数量:</strong> {{ cart.item_count }}</p>
      <p><strong>商品小计:</strong> {{ cart.items_subtotal_price | money }}</p>
      <p><strong>总价:</strong> {{ cart.total_price | money }}</p>
      
      {% if cart.total_discount > 0 %}
        <p class="discount"><strong>优惠:</strong> -{{ cart.total_discount | money }}</p>
      {% endif %}
    </div>
  {% else %}
    <div class="empty-cart">
      <h2>购物车为空</h2>
      <p>您的购物车中还没有商品</p>
      <a href="{{ routes.all_products_collection_url }}" class="btn btn-primary">开始购物</a>
    </div>
  {% endif %}
</div>购物车商品
商品列表
<!-- 购物车商品列表 -->
{% if cart.item_count > 0 %}
  <div class="cart-items">
    {% for item in cart.items %}
      <div class="cart-item" data-variant-id="{{ item.variant.id }}">
        <div class="item-image">
          <img src="{{ item.image | img_url: '150x150' }}" 
               alt="{{ item.product.title }}"
               loading="lazy" />
        </div>
        
        <div class="item-details">
          <h3 class="item-title">
            <a href="{{ item.product.url }}">{{ item.product.title }}</a>
          </h3>
          
          {% unless item.variant.title == 'Default Title' %}
            <p class="item-variant">{{ item.variant.title }}</p>
          {% endunless %}
          
          {% if item.vendor != blank %}
            <p class="item-vendor">品牌: {{ item.vendor }}</p>
          {% endif %}
          
          {% if item.sku != blank %}
            <p class="item-sku">SKU: {{ item.sku }}</p>
          {% endif %}
        </div>
        
        <div class="item-price">
          <div class="price-per-item">
            {% if item.original_price != item.final_price %}
              <span class="original-price"><s>{{ item.original_price | money }}</s></span>
              <span class="final-price">{{ item.final_price | money }}</span>
            {% else %}
              <span class="price">{{ item.price | money }}</span>
            {% endif %}
          </div>
        </div>
        
        <div class="item-quantity">
          <form action="{{ routes.cart_change_url }}" method="post" class="quantity-form">
            <div class="quantity-controls">
              <button type="button" class="quantity-decrease" 
                      onclick="updateQuantity({{ item.key }}, {{ item.quantity | minus: 1 }})">-</button>
              <input type="number" 
                     name="quantity" 
                     value="{{ item.quantity }}" 
                     min="0"
                     class="quantity-input"
                     onchange="updateQuantity({{ item.key }}, this.value)">
              <button type="button" class="quantity-increase"
                      onclick="updateQuantity({{ item.key }}, {{ item.quantity | plus: 1 }})">+</button>
            </div>
          </form>
        </div>
        
        <div class="item-total">
          <span class="line-price">{{ item.final_line_price | money }}</span>
        </div>
        
        <div class="item-actions">
          <button type="button" 
                  class="remove-item" 
                  onclick="removeItem({{ item.key }})">
            删除
          </button>
        </div>
      </div>
    {% endfor %}
  </div>
{% endif %}购物车计算
价格摘要
<!-- 购物车价格摘要 -->
<div class="cart-totals">
  <table class="totals-table">
    <tr>
      <td>商品小计:</td>
      <td>{{ cart.items_subtotal_price | money }}</td>
    </tr>
    
    {% if cart.cart_level_discount_applications.size > 0 %}
      {% for discount in cart.cart_level_discount_applications %}
        <tr class="discount">
          <td>优惠 ({{ discount.title }}):</td>
          <td>-{{ discount.total_allocated_amount | money }}</td>
        </tr>
      {% endfor %}
    {% endif %}
    
    {% comment %} 运费计算需要在结账页面 {% endcomment %}
    <tr class="shipping-note">
      <td colspan="2">
        <small>运费将在结账时计算</small>
      </td>
    </tr>
    
    <tr class="total">
      <td><strong>小计:</strong></td>
      <td><strong>{{ cart.total_price | money }}</strong></td>
    </tr>
  </table>
</div>购物车操作
添加商品
<!-- 添加商品到购物车 -->
<form action="{{ routes.cart_add_url }}" method="post" class="product-form">
  <input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
  
  <div class="quantity-selector">
    <label for="quantity">数量:</label>
    <input type="number" id="quantity" name="quantity" value="1" min="1">
  </div>
  
  <button type="submit" class="btn btn-primary add-to-cart">
    加入购物车
  </button>
</form>
 
<script>
// Ajax 添加商品
document.querySelector('.product-form').addEventListener('submit', function(e) {
  e.preventDefault()
  
  const formData = new FormData(this)
  
  fetch('/cart/add.js', {
    method: 'POST',
    body: formData
  })
  .then(response => response.json())
  .then(data => {
    // 更新购物车UI
    updateCartDrawer()
    showAddToCartNotification(data)
  })
  .catch(error => {
    console.error('添加失败:', error)
  })
})
</script>更新数量
<script>
function updateQuantity(key, quantity) {
  fetch('/cart/change.js', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      id: key,
      quantity: quantity
    })
  })
  .then(response => response.json())
  .then(cart => {
    // 重新加载购物车页面或更新UI
    location.reload()
  })
}
 
function removeItem(key) {
  updateQuantity(key, 0)
}
</script>购物车抽屉
侧边栏购物车
<!-- 购物车抽屉 -->
<div id="cart-drawer" class="cart-drawer">
  <div class="cart-drawer-header">
    <h3>购物车 (<span id="cart-count">{{ cart.item_count }}</span>)</h3>
    <button type="button" class="close-drawer">×</button>
  </div>
  
  <div class="cart-drawer-body">
    {% if cart.item_count > 0 %}
      <div class="cart-items-mini">
        {% for item in cart.items %}
          <div class="mini-cart-item">
            <img src="{{ item.image | img_url: '80x80' }}" alt="{{ item.title }}">
            <div class="item-info">
              <h4>{{ item.product.title }}</h4>
              <p>{{ item.quantity }} × {{ item.final_price | money }}</p>
            </div>
            <button onclick="removeItem({{ item.key }})" class="remove-mini">×</button>
          </div>
        {% endfor %}
      </div>
      
      <div class="cart-drawer-footer">
        <div class="cart-total">
          <strong>总计: {{ cart.total_price | money }}</strong>
        </div>
        <div class="cart-actions">
          <a href="{{ routes.cart_url }}" class="btn btn-outline">查看购物车</a>
          <a href="/checkout" class="btn btn-primary">立即结账</a>
        </div>
      </div>
    {% else %}
      <div class="empty-cart-drawer">
        <p>购物车为空</p>
      </div>
    {% endif %}
  </div>
</div>优惠券和折扣
优惠码输入
<!-- 优惠码表单 -->
<div class="discount-form">
  <h4>优惠码</h4>
  <form action="{{ routes.cart_url }}" method="post" class="coupon-form">
    <div class="input-group">
      <input type="text" 
             name="discount" 
             placeholder="输入优惠码"
             value="{{ cart.discount.code }}"
             class="discount-input">
      <button type="submit" class="btn btn-outline">应用</button>
    </div>
  </form>
  
  {% if cart.discount %}
    <div class="applied-discount">
      <span>已应用: {{ cart.discount.code }}</span>
      <span class="discount-amount">-{{ cart.discount.amount | money }}</span>
      <a href="{{ routes.cart_url }}?discount=" class="remove-discount">移除</a>
    </div>
  {% endif %}
</div>结账流程
结账按钮
<!-- 结账区域 -->
<div class="checkout-section">
  {% if cart.item_count > 0 %}
    <div class="checkout-total">
      <h3>订单总计: {{ cart.total_price | money }}</h3>
    </div>
    
    <div class="checkout-buttons">
      <button type="submit" 
              name="add" 
              class="btn btn-primary btn-full checkout-btn"
              onclick="proceedToCheckout()">
        立即结账
      </button>
      
      <!-- PayPal 快速结账 -->
      {% if shop.paypal_express_checkout %}
        <div class="paypal-express">
          <button class="paypal-button">PayPal 快速支付</button>
        </div>
      {% endif %}
      
      <!-- Apple Pay / Google Pay -->
      <div class="digital-wallets">
        <button class="apple-pay-button" style="display: none;">Apple Pay</button>
        <button class="google-pay-button" style="display: none;">Google Pay</button>
      </div>
    </div>
    
    <div class="checkout-notes">
      <label for="cart-note">订单备注:</label>
      <textarea id="cart-note" 
                name="note" 
                placeholder="特殊要求或备注信息"
                onchange="updateCartNote(this.value)">{{ cart.note }}</textarea>
    </div>
  {% endif %}
</div>
 
<script>
function proceedToCheckout() {
  window.location.href = '/checkout'
}
 
function updateCartNote(note) {
  fetch('/cart/update.js', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      note: note
    })
  })
}
</script>购物车持久化
本地存储
<script>
// 购物车状态管理
const CartManager = {
  // 获取购物车数据
  getCart: function() {
    return fetch('/cart.js')
      .then(response => response.json())
  },
  
  // 添加商品
  addItem: function(variantId, quantity = 1, properties = {}) {
    return fetch('/cart/add.js', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        id: variantId,
        quantity: quantity,
        properties: properties
      })
    }).then(response => response.json())
  },
  
  // 更新商品数量
  updateItem: function(key, quantity) {
    return fetch('/cart/change.js', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        id: key,
        quantity: quantity
      })
    }).then(response => response.json())
  },
  
  // 清空购物车
  clearCart: function() {
    return fetch('/cart/clear.js', {
      method: 'POST'
    }).then(response => response.json())
  },
  
  // 更新购物车UI
  updateCartUI: function(cart) {
    document.getElementById('cart-count').textContent = cart.item_count
    // 更新其他UI元素
  }
}
 
// 页面加载时初始化购物车
document.addEventListener('DOMContentLoaded', function() {
  CartManager.getCart().then(cart => {
    CartManager.updateCartUI(cart)
  })
})
</script>性能优化
Ajax 购物车
<!-- 购物车数据预加载 -->
<script>
window.cartData = {{ cart | json }};
 
// 异步更新购物车
function refreshCart() {
  return fetch('/cart.js')
    .then(response => response.json())
    .then(cart => {
      window.cartData = cart
      updateCartDisplay(cart)
      return cart
    })
}
 
function updateCartDisplay(cart) {
  // 更新购物车计数
  document.querySelectorAll('.cart-count').forEach(el => {
    el.textContent = cart.item_count
  })
  
  // 更新总价显示
  document.querySelectorAll('.cart-total').forEach(el => {
    el.textContent = formatMoney(cart.total_price)
  })
}
 
function formatMoney(cents) {
  return '¥' + (cents / 100).toFixed(2)
}
</script>调试工具
购物车调试
<!-- 购物车调试信息 -->
{% if request.design_mode %}
  <div class="cart-debug" style="margin-top: 2rem; padding: 1rem; background: #fff3cd; font-family: monospace; font-size: 12px;">
    <h4>购物车调试信息</h4>
    
    <div><strong>基本信息:</strong></div>
    <ul>
      <li>商品数量: {{ cart.item_count }}</li>
      <li>商品小计: {{ cart.items_subtotal_price | money }}</li>
      <li>总价: {{ cart.total_price | money }}</li>
      <li>折扣金额: {{ cart.total_discount | money }}</li>
      <li>总重量: {{ cart.total_weight }}g</li>
    </ul>
    
    <div><strong>商品列表:</strong></div>
    {% for item in cart.items %}
      <div style="margin: 10px 0; padding: 10px; border: 1px solid #ddd;">
        <strong>{{ item.product.title }}</strong><br>
        变体: {{ item.variant.title }}<br>
        数量: {{ item.quantity }}<br>
        单价: {{ item.price | money }}<br>
        小计: {{ item.line_price | money }}<br>
        Key: {{ item.key }}
      </div>
    {% endfor %}
  </div>
{% endif %}下一步学习
现在您已经掌握了购物车对象的使用,建议继续学习:
- 全局对象详解 - 了解更多全局对象
 - 产品对象详解 - 深入了解产品相关对象
 - 客户对象详解 - 学习客户相关功能
 - 高级 Liquid 技巧 - 学习更高级的模板技巧
 
最后更新时间: