购物车对象详解
购物车对象包含了用户当前购物车中的所有商品信息、价格计算、运费、税费等。掌握购物车对象是构建完整电商体验的关键。
购物车基本信息
购物车状态
<!-- 购物车基本信息 -->
<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 技巧 - 学习更高级的模板技巧
最后更新时间: