产品对象详解
产品对象是 Shopify Liquid 中最重要和最复杂的对象之一。它包含了商品的所有信息,包括基本属性、变体、图片、选项等。掌握产品对象的使用对于构建功能完整的电商主题至关重要。
产品基本属性
基础信息
<!-- 产品基本信息 -->
<div class="product-info" itemscope itemtype="http://schema.org/Product">
<h1 itemprop="name">{{ product.title }}</h1>
<div class="product-meta">
<p class="vendor">品牌: <span itemprop="brand">{{ product.vendor }}</span></p>
<p class="product-type">分类: {{ product.type }}</p>
<p class="sku" itemprop="sku">SKU: {{ product.selected_or_first_available_variant.sku }}</p>
</div>
<div class="product-description" itemprop="description">
{{ product.description }}
</div>
</div>
价格信息
<!-- 产品价格展示 -->
<div class="product-price" itemscope itemtype="http://schema.org/Offer">
{% assign current_variant = product.selected_or_first_available_variant %}
<meta itemprop="priceCurrency" content="{{ shop.currency }}">
<meta itemprop="price" content="{{ current_variant.price | money_without_currency }}">
{% if current_variant.compare_at_price > current_variant.price %}
<span class="price-compare">
原价: <s>{{ current_variant.compare_at_price | money }}</s>
</span>
<span class="price-current sale">
现价: {{ current_variant.price | money }}
</span>
<span class="price-save">
节省: {{ current_variant.compare_at_price | minus: current_variant.price | money }}
({{ current_variant.compare_at_price | minus: current_variant.price | times: 100 | divided_by: current_variant.compare_at_price }}% OFF)
</span>
{% else %}
<span class="price-current">
{{ current_variant.price | money }}
</span>
{% endif %}
{% comment %} 价格范围显示 {% endcomment %}
{% unless product.has_only_default_variant %}
<div class="price-range">
{% if product.price_varies %}
<span>价格范围: {{ product.price_min | money }} - {{ product.price_max | money }}</span>
{% endif %}
{% if product.compare_at_price_varies %}
<span>原价范围: {{ product.compare_at_price_min | money }} - {{ product.compare_at_price_max | money }}</span>
{% endif %}
</div>
{% endunless %}
</div>
库存状态
<!-- 库存信息 -->
<div class="product-availability">
{% assign current_variant = product.selected_or_first_available_variant %}
{% if current_variant.available %}
<span class="in-stock" itemprop="availability" content="http://schema.org/InStock">
{% if current_variant.inventory_management %}
{% if current_variant.inventory_quantity > 0 %}
有库存 ({{ current_variant.inventory_quantity }} 件)
{% else %}
有库存
{% endif %}
{% else %}
有库存
{% endif %}
</span>
{% else %}
<span class="out-of-stock" itemprop="availability" content="http://schema.org/OutOfStock">
缺货
</span>
{% endif %}
{% comment %} 低库存警告 {% endcomment %}
{% if current_variant.inventory_quantity <= 5 and current_variant.inventory_quantity > 0 %}
<div class="low-stock-warning">
仅剩 {{ current_variant.inventory_quantity }} 件!
</div>
{% endif %}
</div>
产品图片
主图展示
<!-- 产品主图 -->
<div class="product-images">
{% assign featured_image = product.featured_image | default: product.images.first %}
{% if featured_image %}
<div class="main-image">
<img src="{{ featured_image | img_url: '800x800' }}"
srcset="{{ featured_image | img_url: '400x400' }} 400w,
{{ featured_image | img_url: '600x600' }} 600w,
{{ featured_image | img_url: '800x800' }} 800w,
{{ featured_image | img_url: '1000x1000' }} 1000w"
sizes="(max-width: 768px) 100vw, 50vw"
alt="{{ featured_image.alt | default: product.title }}"
itemprop="image"
loading="lazy" />
</div>
{% endif %}
</div>
图片画廊
<!-- 产品图片画廊 -->
<div class="product-gallery">
{% if product.images.size > 1 %}
<div class="thumbnail-list">
{% for image in product.images %}
<button class="thumbnail {% if forloop.first %}active{% endif %}"
data-image-id="{{ image.id }}"
type="button">
<img src="{{ image | img_url: '100x100' }}"
alt="{{ image.alt | default: product.title }}"
loading="lazy" />
</button>
{% endfor %}
</div>
<div class="main-gallery">
{% for image in product.images %}
<div class="gallery-image {% if forloop.first %}active{% endif %}"
data-image-id="{{ image.id }}">
<img src="{{ image | img_url: '800x800' }}"
srcset="{{ image | img_url: '400x400' }} 400w,
{{ image | img_url: '600x600' }} 600w,
{{ image | img_url: '800x800' }} 800w,
{{ image | img_url: '1200x1200' }} 1200w"
sizes="(max-width: 768px) 100vw, 60vw"
alt="{{ image.alt | default: product.title }}"
loading="lazy" />
</div>
{% endfor %}
</div>
{% endif %}
</div>
变体关联图片
<!-- 变体图片映射 -->
<div class="variant-images">
{% for variant in product.variants %}
{% if variant.featured_image %}
<div class="variant-image"
data-variant-id="{{ variant.id }}"
style="display: none;">
<img src="{{ variant.featured_image | img_url: '800x800' }}"
alt="{{ variant.title }}"
loading="lazy" />
</div>
{% endif %}
{% endfor %}
</div>
<script>
// 变体切换时更新图片
document.addEventListener('DOMContentLoaded', function() {
const variantSelector = document.querySelector('[name="id"]')
if (variantSelector) {
variantSelector.addEventListener('change', function() {
const variantId = this.value
const variantImage = document.querySelector(`[data-variant-id="${variantId}"]`)
// 隐藏所有变体图片
document.querySelectorAll('.variant-image').forEach(img => {
img.style.display = 'none'
})
// 显示当前变体图片
if (variantImage) {
variantImage.style.display = 'block'
}
})
}
})
</script>
产品变体
基本变体信息
<!-- 产品变体选择 -->
<div class="product-variants">
{% unless product.has_only_default_variant %}
{% for option in product.options_with_values %}
<div class="variant-option">
<label for="option-{{ option.position }}">{{ option.name }}:</label>
{% if option.name == 'Color' or option.name == '颜色' %}
<!-- 颜色选择器 -->
<div class="color-swatches">
{% for value in option.values %}
{% assign option_id = 'option-' | append: option.position | append: '-' | append: forloop.index %}
<input type="radio"
id="{{ option_id }}"
name="options[{{ option.name }}]"
value="{{ value }}"
{% if option.selected_value == value %}checked{% endif %}>
<label for="{{ option_id }}"
class="color-swatch"
style="background-color: {{ value | downcase }}"
title="{{ value }}">
<span class="sr-only">{{ value }}</span>
</label>
{% endfor %}
</div>
{% elsif option.name == 'Size' or option.name == '尺寸' %}
<!-- 尺寸选择器 -->
<div class="size-options">
{% for value in option.values %}
{% assign option_id = 'option-' | append: option.position | append: '-' | append: forloop.index %}
<input type="radio"
id="{{ option_id }}"
name="options[{{ option.name }}]"
value="{{ value }}"
{% if option.selected_value == value %}checked{% endif %}>
<label for="{{ option_id }}" class="size-option">
{{ value }}
</label>
{% endfor %}
</div>
{% else %}
<!-- 下拉选择器 -->
<select name="options[{{ option.name }}]"
id="option-{{ option.position }}">
{% for value in option.values %}
<option value="{{ value }}"
{% if option.selected_value == value %}selected{% endif %}>
{{ value }}
</option>
{% endfor %}
</select>
{% endif %}
</div>
{% endfor %}
{% endunless %}
</div>
变体数据映射
<!-- 变体数据 JSON -->
<script type="application/json" id="product-variants">
{
"variants": [
{% for variant in product.variants %}
{
"id": {{ variant.id }},
"title": "{{ variant.title | escape }}",
"sku": "{{ variant.sku | escape }}",
"price": {{ variant.price }},
"compare_at_price": {% if variant.compare_at_price %}{{ variant.compare_at_price }}{% else %}null{% endif %},
"available": {{ variant.available | json }},
"inventory_quantity": {% if variant.inventory_quantity %}{{ variant.inventory_quantity }}{% else %}null{% endif %},
"inventory_management": {% if variant.inventory_management %}"{{ variant.inventory_management }}"{% else %}null{% endif %},
"weight": {{ variant.weight }},
"weight_unit": "{{ variant.weight_unit }}",
"featured_image": {% if variant.featured_image %}"{{ variant.featured_image | img_url: '800x800' }}"{% else %}null{% endif %},
"options": [
{% for option in variant.options %}
"{{ option | escape }}"{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}{% unless forloop.last %},{% endunless %}
{% endfor %}
],
"options": [
{% for option in product.options %}
{
"name": "{{ option | escape }}",
"position": {{ forloop.index }},
"values": [
{% assign option_values = product.options_with_values[forloop.index0].values %}
{% for value in option_values %}
"{{ value | escape }}"{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}
</script>
动态变体选择
<!-- 智能变体选择器 -->
<div class="smart-variant-selector">
{% for option in product.options_with_values %}
<div class="option-group" data-option-position="{{ option.position }}">
<h4>{{ option.name }}:</h4>
<div class="option-values">
{% for value in option.values %}
{% assign available_in_option = false %}
{% for variant in product.variants %}
{% if variant.option1 == value or variant.option2 == value or variant.option3 == value %}
{% if variant.available %}
{% assign available_in_option = true %}
{% break %}
{% endif %}
{% endif %}
{% endfor %}
<button type="button"
class="option-value {% unless available_in_option %}unavailable{% endunless %}"
data-value="{{ value }}"
{% unless available_in_option %}disabled{% endunless %}>
{{ value }}
{% unless available_in_option %}
<span class="unavailable-text">(缺货)</span>
{% endunless %}
</button>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
产品标签和分类
标签处理
<!-- 产品标签 -->
<div class="product-tags">
{% if product.tags.size > 0 %}
<h4>标签:</h4>
<div class="tag-list">
{% for tag in product.tags %}
<a href="{{ blog.url }}/tagged/{{ tag | handle }}"
class="tag"
rel="tag">
{{ tag }}
</a>
{% endfor %}
</div>
{% endif %}
</div>
<!-- 基于标签的功能 -->
<div class="product-features">
{% if product.tags contains 'new' %}
<span class="badge new">新品</span>
{% endif %}
{% if product.tags contains 'sale' %}
<span class="badge sale">促销</span>
{% endif %}
{% if product.tags contains 'limited' %}
<span class="badge limited">限量</span>
{% endif %}
{% if product.tags contains 'eco-friendly' %}
<span class="badge eco">环保</span>
{% endif %}
</div>
集合关联
<!-- 产品所属集合 -->
<div class="product-collections">
{% if product.collections.size > 0 %}
<h4>分类:</h4>
<nav class="collection-breadcrumb">
{% for collection in product.collections %}
<a href="{{ collection.url }}">{{ collection.title }}</a>
{% unless forloop.last %} / {% endunless %}
{% endfor %}
</nav>
{% endif %}
</div>
产品元字段
自定义字段
<!-- 产品元字段 -->
<div class="product-metafields">
{% comment %} 材质信息 {% endcomment %}
{% if product.metafields.custom.material %}
<div class="metafield-item">
<h4>材质:</h4>
<p>{{ product.metafields.custom.material.value }}</p>
</div>
{% endif %}
{% comment %} 尺寸指南 {% endcomment %}
{% if product.metafields.custom.size_guide %}
<div class="metafield-item">
<h4>尺寸指南:</h4>
<div class="size-guide">
{{ product.metafields.custom.size_guide.value }}
</div>
</div>
{% endif %}
{% comment %} 护理说明 {% endcomment %}
{% if product.metafields.custom.care_instructions %}
<div class="metafield-item">
<h4>护理说明:</h4>
<div class="care-instructions">
{{ product.metafields.custom.care_instructions.value }}
</div>
</div>
{% endif %}
{% comment %} 技术规格 {% endcomment %}
{% if product.metafields.custom.specifications %}
<div class="metafield-item">
<h4>技术规格:</h4>
<div class="specifications">
{{ product.metafields.custom.specifications.value }}
</div>
</div>
{% endif %}
</div>
结构化数据
<!-- 产品结构化数据 -->
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "Product",
"name": "{{ product.title | escape }}",
"description": "{{ product.description | strip_html | truncate: 200 | escape }}",
"image": [
{% for image in product.images limit: 3 %}
"{{ image | img_url: '800x800' }}"{% unless forloop.last %},{% endunless %}
{% endfor %}
],
"brand": {
"@type": "Brand",
"name": "{{ product.vendor | escape }}"
},
"sku": "{{ product.selected_or_first_available_variant.sku }}",
"mpn": "{{ product.selected_or_first_available_variant.barcode }}",
"offers": {
"@type": "Offer",
"url": "{{ shop.url }}{{ product.url }}",
"priceCurrency": "{{ shop.currency }}",
"price": "{{ product.selected_or_first_available_variant.price | money_without_currency }}",
{% if product.selected_or_first_available_variant.compare_at_price > product.selected_or_first_available_variant.price %}
"priceValidUntil": "{{ 'now' | date: '%Y' | plus: 1 }}-12-31",
{% endif %}
"availability": "{% if product.selected_or_first_available_variant.available %}http://schema.org/InStock{% else %}http://schema.org/OutOfStock{% endif %}",
"seller": {
"@type": "Organization",
"name": "{{ shop.name | escape }}"
}
}
{% if product.metafields.reviews.rating %}
,"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "{{ product.metafields.reviews.rating.value }}",
"ratingCount": "{{ product.metafields.reviews.count.value }}"
}
{% endif %}
}
</script>
高级产品功能
产品推荐
<!-- 相关产品推荐 -->
<div class="related-products">
<h3>相关产品</h3>
{% comment %} 基于标签的推荐 {% endcomment %}
{% assign related_products = collections.all.products | where: 'tags', product.tags.first %}
{% assign related_products = related_products | where: 'available' %}
{% assign related_products = related_products | remove: product %}
{% if related_products.size == 0 %}
{% comment %} 基于类型的推荐 {% endcomment %}
{% assign related_products = collections.all.products | where: 'type', product.type %}
{% assign related_products = related_products | where: 'available' %}
{% assign related_products = related_products | remove: product %}
{% endif %}
{% if related_products.size == 0 %}
{% comment %} 基于供应商的推荐 {% endcomment %}
{% assign related_products = collections.all.products | where: 'vendor', product.vendor %}
{% assign related_products = related_products | where: 'available' %}
{% assign related_products = related_products | remove: product %}
{% endif %}
{% if related_products.size > 0 %}
<div class="product-grid">
{% for related_product in related_products limit: 4 %}
<div class="product-card">
<a href="{{ related_product.url }}">
<img src="{{ related_product.featured_image | img_url: '300x300' }}"
alt="{{ related_product.title }}"
loading="lazy" />
<h4>{{ related_product.title }}</h4>
<p class="price">{{ related_product.price | money }}</p>
</a>
</div>
{% endfor %}
</div>
{% endif %}
</div>
库存追踪
<!-- 库存监控 -->
<div class="inventory-tracker" data-product-id="{{ product.id }}">
{% for variant in product.variants %}
<div class="variant-inventory"
data-variant-id="{{ variant.id }}"
data-inventory="{{ variant.inventory_quantity }}"
data-policy="{{ variant.inventory_policy }}">
{% if variant.inventory_management %}
{% if variant.inventory_quantity <= 0 %}
<span class="status out-of-stock">{{ variant.title }} - 缺货</span>
{% elsif variant.inventory_quantity <= 5 %}
<span class="status low-stock">{{ variant.title }} - 仅剩 {{ variant.inventory_quantity }} 件</span>
{% else %}
<span class="status in-stock">{{ variant.title }} - 有库存</span>
{% endif %}
{% else %}
<span class="status available">{{ variant.title }} - 有货</span>
{% endif %}
</div>
{% endfor %}
</div>
购买按钮组
<!-- 产品购买区域 -->
<div class="product-purchase">
<form action="/cart/add" method="post" enctype="multipart/form-data" class="product-form">
<!-- 变体选择器 -->
<div class="variant-selector">
{% unless product.has_only_default_variant %}
<select name="id" id="product-variants" class="variant-dropdown">
{% for variant in product.variants %}
<option value="{{ variant.id }}"
{% unless variant.available %}disabled{% endunless %}
data-price="{{ variant.price | money }}"
data-compare-price="{{ variant.compare_at_price | money }}"
data-inventory="{{ variant.inventory_quantity }}">
{{ variant.title }}
{% unless variant.available %} - 缺货{% endunless %}
- {{ variant.price | money }}
</option>
{% endfor %}
</select>
{% else %}
<input type="hidden" name="id" value="{{ product.variants.first.id }}">
{% endunless %}
</div>
<!-- 数量选择器 -->
<div class="quantity-selector">
<label for="quantity">数量:</label>
<div class="quantity-input">
<button type="button" class="quantity-decrease" aria-label="减少数量">-</button>
<input type="number"
id="quantity"
name="quantity"
value="1"
min="1"
class="quantity-field">
<button type="button" class="quantity-increase" aria-label="增加数量">+</button>
</div>
</div>
<!-- 购买按钮 -->
<div class="purchase-buttons">
<button type="submit"
class="btn btn-primary add-to-cart"
{% unless product.available %}disabled{% endunless %}>
{% if product.available %}
<span class="add-text">加入购物车</span>
<span class="adding-text" style="display: none;">加入中...</span>
{% else %}
缺货
{% endif %}
</button>
<!-- 立即购买按钮 -->
{% if product.available %}
<button type="button" class="btn btn-secondary buy-now">
立即购买
</button>
{% endif %}
<!-- 收藏按钮 -->
<button type="button" class="btn btn-outline wishlist-toggle" data-product-id="{{ product.id }}">
<span class="wishlist-add">收藏</span>
<span class="wishlist-remove" style="display: none;">取消收藏</span>
</button>
</div>
<!-- 购买保证 -->
<div class="purchase-guarantees">
<div class="guarantee-item">
<span class="icon">🚚</span>
<span>免费配送</span>
</div>
<div class="guarantee-item">
<span class="icon">↩️</span>
<span>30天退货</span>
</div>
<div class="guarantee-item">
<span class="icon">🔒</span>
<span>安全支付</span>
</div>
</div>
</form>
</div>
性能优化
图片懒加载
<!-- 性能优化的图片加载 -->
<div class="product-images-optimized">
{% assign featured_image = product.featured_image %}
<!-- 主图(立即加载) -->
{% if featured_image %}
<div class="hero-image">
<img src="{{ featured_image | img_url: '800x800' }}"
srcset="{{ featured_image | img_url: '400x400' }} 400w,
{{ featured_image | img_url: '600x600' }} 600w,
{{ featured_image | img_url: '800x800' }} 800w,
{{ featured_image | img_url: '1200x1200' }} 1200w"
sizes="(max-width: 768px) 100vw, 50vw"
alt="{{ featured_image.alt | default: product.title }}"
width="800"
height="800" />
</div>
{% endif %}
<!-- 其他图片(懒加载) -->
{% for image in product.images offset: 1 %}
<div class="gallery-image">
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 800'%3E%3C/svg%3E"
data-src="{{ image | img_url: '800x800' }}"
data-srcset="{{ image | img_url: '400x400' }} 400w,
{{ image | img_url: '600x600' }} 600w,
{{ image | img_url: '800x800' }} 800w,
{{ image | img_url: '1200x1200' }} 1200w"
data-sizes="(max-width: 768px) 100vw, 50vw"
alt="{{ image.alt | default: product.title }}"
class="lazyload"
width="800"
height="800" />
</div>
{% endfor %}
</div>
数据预加载
<!-- 产品数据预加载 -->
<script>
// 预加载产品数据
window.productData = {
id: {{ product.id }},
handle: '{{ product.handle }}',
title: '{{ product.title | escape }}',
vendor: '{{ product.vendor | escape }}',
type: '{{ product.type | escape }}',
available: {{ product.available | json }},
price: {{ product.price }},
compare_at_price: {% if product.compare_at_price %}{{ product.compare_at_price }}{% else %}null{% endif %},
price_varies: {{ product.price_varies | json }},
variants: {{ product.variants | json }},
images: [
{% for image in product.images %}
{
id: {{ image.id }},
url: '{{ image | img_url: '800x800' }}',
alt: '{{ image.alt | escape }}'
}{% unless forloop.last %},{% endunless %}
{% endfor %}
],
options: {{ product.options | json }},
tags: {{ product.tags | json }}
}
</script>
调试和测试
产品数据调试
<!-- 产品调试信息 -->
{% if request.design_mode %}
<div class="product-debug" style="margin-top: 2rem; padding: 1rem; background: #f5f5f5; font-family: monospace; font-size: 12px;">
<h4>产品调试信息</h4>
<div><strong>基本信息:</strong></div>
<ul>
<li>ID: {{ product.id }}</li>
<li>Handle: {{ product.handle }}</li>
<li>Title: {{ product.title }}</li>
<li>Vendor: {{ product.vendor }}</li>
<li>Type: {{ product.type }}</li>
<li>Available: {{ product.available }}</li>
<li>Created: {{ product.created_at | date: '%Y-%m-%d %H:%M' }}</li>
<li>Updated: {{ product.updated_at | date: '%Y-%m-%d %H:%M' }}</li>
</ul>
<div><strong>价格信息:</strong></div>
<ul>
<li>Price: {{ product.price | money }}</li>
<li>Compare at price: {{ product.compare_at_price | money }}</li>
<li>Price varies: {{ product.price_varies }}</li>
<li>Price min: {{ product.price_min | money }}</li>
<li>Price max: {{ product.price_max | money }}</li>
</ul>
<div><strong>变体信息:</strong></div>
<ul>
<li>Variants count: {{ product.variants.size }}</li>
<li>Has only default variant: {{ product.has_only_default_variant }}</li>
<li>Options: {{ product.options | join: ', ' }}</li>
</ul>
<div><strong>媒体信息:</strong></div>
<ul>
<li>Images count: {{ product.images.size }}</li>
<li>Featured image: {% if product.featured_image %}{{ product.featured_image.alt }}{% else %}None{% endif %}</li>
</ul>
<div><strong>分类信息:</strong></div>
<ul>
<li>Collections: {{ product.collections | map: 'title' | join: ', ' }}</li>
<li>Tags: {{ product.tags | join: ', ' }}</li>
</ul>
</div>
{% endif %}
下一步学习
现在您已经掌握了产品对象的详细使用,建议继续学习:
- 客户对象详解 - 学习客户相关功能
- 购物车对象详解 - 掌握购物车实现
- 全局对象详解 - 了解更多全局对象
- 高级 Liquid 技巧 - 学习更高级的技巧
最后更新时间: