Skip to Content
🎉 探索 Shopify 的无限可能 结构化知识 + 实战案例,持续更新中...
Liquid 开发Liquid 标签

标签和控制结构

Liquid 标签是模板语言的核心,用于创建逻辑和控制流。本指南将详细介绍所有可用的标签和它们的高级用法。

标签基础

标签语法

<!-- 基本标签语法 --> {% tag_name %} <!-- 带参数的标签 --> {% tag_name parameter %} <!-- 标签块 --> {% tag_name %} 内容 {% endtag_name %} <!-- 自闭合标签 --> {% tag_name parameter %}

空白控制

<!-- 控制标签周围的空白 --> {%- if condition -%} 内容 {%- endif -%} <!-- 只控制左侧空白 --> {%- assign var = value %} <!-- 只控制右侧空白 --> {% assign var = value -%}

控制流标签

if/elsif/else

<!-- 基本条件判断 --> {% if product.available %} <button class="add-to-cart">加入购物车</button> {% endif %} <!-- 多重条件 --> {% if customer.tags contains 'vip' %} <span class="vip-badge">VIP 客户</span> {% elsif customer.tags contains 'member' %} <span class="member-badge">会员</span> {% else %} <span class="guest-badge">访客</span> {% endif %} <!-- 复杂条件表达式 --> {% if product.available and product.price < 10000 %} <span class="affordable-available">经济实惠,现货供应</span> {% elsif product.available and product.price >= 10000 %} <span class="premium-available">高端商品,现货供应</span> {% elsif product.price < 10000 %} <span class="affordable-unavailable">经济实惠,暂时缺货</span> {% else %} <span class="premium-unavailable">高端商品,暂时缺货</span> {% endif %}

unless

<!-- unless 是 if 的否定形式 --> {% unless product.available %} <div class="out-of-stock-notice"> <p>此商品暂时缺货</p> <button class="notify-btn">到货通知</button> </div> {% endunless %} <!-- 等同于 --> {% if product.available == false %} <div class="out-of-stock-notice"> <p>此商品暂时缺货</p> <button class="notify-btn">到货通知</button> </div> {% endif %} <!-- unless 与 else 组合 --> {% unless customer %} <div class="login-prompt"> <p>请登录以享受会员价格</p> <a href="/account/login">立即登录</a> </div> {% else %} <div class="welcome-back"> <p>欢迎回来,{{ customer.first_name }}!</p> </div> {% endunless %}

case/when

<!-- case 语句用于多分支选择 --> {% case product.type %} {% when 'Electronics' %} <div class="electronics-info"> <span class="icon">📱</span> <p>电子产品 - 1年保修</p> </div> {% when 'Clothing' %} <div class="clothing-info"> <span class="icon">👕</span> <p>服装 - 7天无理由退换</p> </div> {% when 'Books' %} <div class="books-info"> <span class="icon">📚</span> <p>图书 - 正版保证</p> </div> {% else %} <div class="general-info"> <span class="icon">🎁</span> <p>其他商品 - 质量保证</p> </div> {% endcase %} <!-- 多值匹配 --> {% case customer.tags %} {% when 'vip', 'premium', 'gold' %} <div class="premium-service"> <h3>尊享服务</h3> <ul> <li>免费配送</li> <li>优先客服</li> <li>专属折扣</li> </ul> </div> {% when 'member', 'silver' %} <div class="member-service"> <h3>会员服务</h3> <ul> <li>会员折扣</li> <li>积分奖励</li> </ul> </div> {% else %} <div class="standard-service"> <h3>标准服务</h3> <p>注册成为会员,享受更多优惠!</p> </div> {% endcase %}

循环标签

for 循环

<!-- 基本循环 --> {% for product in collection.products %} <div class="product-item"> <h3>{{ product.title }}</h3> <p>{{ product.price | money }}</p> </div> {% endfor %} <!-- 带限制的循环 --> {% for product in collection.products limit: 8 %} <div class="featured-product"> {{ product.title }} </div> {% endfor %} <!-- 跳过元素的循环 --> {% for product in collection.products offset: 4 limit: 8 %} <div class="product-item"> {{ product.title }} </div> {% endfor %} <!-- 反向循环 --> {% for product in collection.products reversed %} <div class="product-item"> <span class="position">{{ forloop.rindex }}</span> {{ product.title }} </div> {% endfor %}

forloop 对象

{% for item in cart.items %} <div class="cart-item" data-index="{{ forloop.index }}"> <!-- forloop.index: 当前索引 (从1开始) --> <span class="item-number">{{ forloop.index }}</span> <!-- forloop.index0: 当前索引 (从0开始) --> <span class="item-id">item-{{ forloop.index0 }}</span> <!-- forloop.rindex: 反向索引 (从末尾开始) --> <span class="remaining">还有 {{ forloop.rindex }} 项</span> <!-- forloop.length: 总长度 --> <span class="total">共 {{ forloop.length }} 项</span> <!-- forloop.first: 是否为第一项 --> {% if forloop.first %} <span class="first-item">首项</span> {% endif %} <!-- forloop.last: 是否为最后一项 --> {% if forloop.last %} <span class="last-item">末项</span> {% endif %} <div class="item-content">{{ item.title }}</div> </div> {% endfor %}

高级循环控制

<!-- continue - 跳过当前迭代 --> {% for product in collection.products %} {% if product.available == false %} {% continue %} {% endif %} {% if product.price > 100000 %} {% continue %} {% endif %} <div class="available-affordable-product"> <h3>{{ product.title }}</h3> <p>{{ product.price | money }}</p> </div> {% endfor %} <!-- break - 提前退出循环 --> {% for product in collection.products %} {% if forloop.index > 6 %} {% break %} {% endif %} <div class="top-product"> <span class="rank">第{{ forloop.index }}名</span> <h3>{{ product.title }}</h3> </div> {% endfor %} <!-- 在break后显示"更多"链接 --> {% assign remaining_count = collection.products.size | minus: 6 %} {% if remaining_count > 0 %} <div class="more-products"> <a href="{{ collection.url }}"> 查看更多 {{ remaining_count }} 个商品 </a> </div> {% endif %}

循环的 else 子句

<!-- 当循环为空时执行else --> {% for product in collection.products %} <div class="product-card"> <h3>{{ product.title }}</h3> <p>{{ product.price | money }}</p> </div> {% else %} <div class="empty-collection"> <h3>暂无商品</h3> <p>该分类下还没有商品,请稍后再来查看。</p> <a href="/collections" class="browse-all">浏览所有分类</a> </div> {% endfor %} <!-- 条件性空状态 --> {% assign available_products = collection.products | where: 'available', true %} {% for product in available_products %} <div class="available-product">{{ product.title }}</div> {% else %} <div class="no-available-products"> <p>该分类下的商品暂时都缺货了</p> <button class="notify-btn">到货通知</button> </div> {% endfor %}

范围循环

<!-- 数字范围循环 --> {% for i in (1..5) %} <span class="rating-star" data-rating="{{ i }}">⭐</span> {% endfor %} <!-- 变量范围循环 --> {% assign start_year = 2020 %} {% assign end_year = 2024 %} {% for year in (start_year..end_year) %} <option value="{{ year }}">{{ year }}年</option> {% endfor %} <!-- 动态范围 --> {% assign max_quantity = product.selected_or_first_available_variant.inventory_quantity | at_most: 10 %} <select name="quantity"> {% for qty in (1..max_quantity) %} <option value="{{ qty }}">{{ qty }}</option> {% endfor %} </select> <!-- 分页范围 --> {% if paginate.pages > 1 %} <div class="pagination"> {% for page in (1..paginate.pages) %} <a href="{{ blog.url }}?page={{ page }}" {% if page == paginate.current_page %}class="current"{% endif %}> {{ page }} </a> {% endfor %} </div> {% endif %}

变量标签

assign

<!-- 基本赋值 --> {% assign product_title = product.title %} {% assign sale_price = product.price | times: 0.8 %} <!-- 字符串操作 --> {% assign product_url = shop.url | append: product.url %} {% assign css_classes = "product-card" | append: " featured" %} <!-- 条件赋值 --> {% if product.available %} {% assign availability_class = "in-stock" %} {% assign availability_text = "有库存" %} {% else %} {% assign availability_class = "out-of-stock" %} {% assign availability_text = "缺货" %} {% endif %} <!-- 复杂计算 --> {% assign discount = product.compare_at_price | minus: product.price %} {% assign discount_percent = discount | times: 100 | divided_by: product.compare_at_price | round %} {% assign savings_text = "节省 " | append: discount_percent | append: "%" %}

capture

<!-- 捕获 HTML 内容 --> {% capture product_gallery %} <div class="product-gallery"> {% for image in product.images %} <div class="gallery-item"> <img src="{{ image | img_url: '400x400' }}" alt="{{ image.alt | escape }}" data-zoom="{{ image | img_url: '1200x1200' }}"> </div> {% endfor %} </div> {% endcapture %} <!-- 捕获动态内容 --> {% capture shipping_calculator %} {% if cart.total_price > 50000 %} <div class="free-shipping"> <span class="icon">🚚</span> <span>免费配送</span> </div> {% else %} {% assign remaining = 50000 | minus: cart.total_price %} <div class="shipping-threshold"> <span>再购买 {{ remaining | money }} 即可免费配送</span> <div class="progress-bar"> {% assign progress = cart.total_price | times: 100 | divided_by: 50000 %} <div class="progress" style="width: {{ progress }}%"></div> </div> </div> {% endif %} {% endcapture %} <!-- 使用捕获的内容 --> <div class="product-details"> {{ product_gallery }} </div> <div class="cart-info"> {{ shipping_calculator }} </div>

increment/decrement

<!-- increment: 创建并递增变量 --> <ul class="product-list"> {% for product in collection.products %} <li class="product-item"> <span class="item-number">{% increment item_counter %}</span> <h3>{{ product.title }}</h3> </li> {% endfor %} </ul> <!-- decrement: 创建并递减变量 --> {% assign total_items = collection.products.size %} <ol class="countdown-list"> {% for product in collection.products %} <li class="countdown-item"> <span class="remaining">还剩 {% decrement countdown %} 个</span> <h3>{{ product.title }}</h3> </li> {% endfor %} </ol> <!-- 多个计数器 --> <div class="category-stats"> {% for product in collection.products %} {% if product.type == 'Electronics' %} 电子产品 #{% increment electronics_count %} {% elsif product.type == 'Clothing' %} 服装 #{% increment clothing_count %} {% endif %} {% endfor %} </div>

模板标签

render

<!-- 基本渲染 --> {% render 'product-card' %} <!-- 传递变量 --> {% render 'product-card', product: product %} <!-- 传递多个变量 --> {% render 'product-card', product: product, show_vendor: true, show_reviews: false, css_class: 'featured' %} <!-- 在循环中渲染 --> <div class="products-grid"> {% for product in collection.products %} {% render 'product-card', product: product, index: forloop.index, is_first: forloop.first %} {% endfor %} </div> <!-- 条件渲染 --> {% if customer %} {% render 'customer-dashboard', customer: customer %} {% else %} {% render 'login-form' %} {% endif %}

高级 render 用法

<!-- 动态模板渲染 --> {% assign template_name = 'product-card-' | append: settings.card_style %} {% render template_name, product: product %} <!-- 渲染带配置的组件 --> {% render 'image-gallery', images: product.images, config: { 'thumbnail_size': '100x100', 'main_size': '600x600', 'zoom_enabled': true, 'lazy_load': true } %} <!-- 错误处理渲染 --> {% assign snippet_exists = 'product-' | append: product.type | downcase %} {% render snippet_exists, product: product %} <!-- 如果snippet不存在,会静默失败 -->

原始内容标签

raw

<!-- 阻止 Liquid 处理内容 --> {% raw %} <script> // 这里的 {{ }} 不会被 Liquid 处理 var productTitle = "{{ product.title }}"; var productPrice = {{ product.price }}; </script> {% endraw %} <!-- 显示 Liquid 代码示例 --> <div class="code-example"> <h4>使用方法:</h4> <code> {% raw %}{{ product.title | upcase }}{% endraw %} </code> </div> <!-- 在教程中显示模板代码 --> <pre class="liquid-code"> {% raw %} {% for product in collection.products %} <h3>{{ product.title }}</h3> <p>{{ product.price | money }}</p> {% endfor %} {% endraw %} </pre>

注释标签

comment

{% comment %} 这是多行注释 可以包含任何内容 包括 Liquid 代码: {{ product.title }} 都不会被处理或显示 {% endcomment %} {% comment %} TODO: 优化产品卡片性能 - 实现图片懒加载 - 减少DOM操作 - 缓存价格计算 {% endcomment %} <!-- 条件注释 --> {% if settings.debug_mode %} {% comment %} 调试信息: - 产品ID: {{ product.id }} - 模板: {{ template }} - 时间: {{ 'now' | date: '%Y-%m-%d %H:%M:%S' }} {% endcomment %} {% endif %}

单行注释

{% # 这是单行注释 %} {% assign price = product.price %} {% # 获取产品价格 %} {% # TODO: 添加变体选择器 %} <div class="product-options"> <!-- 变体选择器将在这里 --> </div>

表单标签

form

<!-- 产品表单 --> {% form 'product', product %} <div class="product-form"> {% if product.variants.size > 1 %} <div class="variant-selector"> <select name="id" class="product-variants"> {% for variant in product.variants %} <option value="{{ variant.id }}" {% unless variant.available %}disabled{% endunless %}> {{ variant.title }} {% unless variant.available %} - 缺货{% endunless %} </option> {% endfor %} </select> </div> {% else %} <input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}"> {% endif %} <div class="quantity-selector"> <label for="quantity">数量:</label> <input type="number" name="quantity" value="1" min="1" max="10"> </div> <button type="submit" class="add-to-cart-btn"> 加入购物车 </button> </div> {% endform %} <!-- 联系表单 --> {% form 'contact' %} <div class="contact-form"> <div class="form-group"> <label for="contact[name]">姓名</label> <input type="text" name="contact[name]" required> </div> <div class="form-group"> <label for="contact[email]">邮箱</label> <input type="email" name="contact[email]" required> </div> <div class="form-group"> <label for="contact[message]">留言</label> <textarea name="contact[message]" rows="5" required></textarea> </div> <button type="submit">发送留言</button> </div> {% endform %}

分页标签

paginate

<!-- 博客分页 --> {% paginate blog.articles by 5 %} <div class="blog-articles"> {% for article in blog.articles %} <article class="blog-post"> <h2><a href="{{ article.url }}">{{ article.title }}</a></h2> <div class="article-meta"> <time>{{ article.published_at | date: '%Y年%m月%d日' }}</time> <span class="author">{{ article.author }}</span> </div> <div class="article-excerpt"> {{ article.excerpt | default: article.content | strip_html | truncate: 200 }} </div> <a href="{{ article.url }}" class="read-more">阅读全文</a> </article> {% endfor %} </div> <!-- 分页导航 --> {% if paginate.pages > 1 %} <nav class="pagination"> {% if paginate.previous %} <a href="{{ paginate.previous.url }}" class="prev">上一页</a> {% endif %} {% for part in paginate.parts %} {% if part.is_link %} <a href="{{ part.url }}">{{ part.title }}</a> {% else %} <span class="current">{{ part.title }}</span> {% endif %} {% endfor %} {% if paginate.next %} <a href="{{ paginate.next.url }}" class="next">下一页</a> {% endif %} </nav> {% endif %} {% endpaginate %}

高级标签组合

嵌套循环和条件

<!-- 产品按类型分组显示 --> {% assign product_types = collection.products | map: 'type' | uniq %} {% for product_type in product_types %} <div class="product-category"> <h2>{{ product_type }}</h2> <div class="products-grid"> {% for product in collection.products %} {% if product.type == product_type %} {% render 'product-card', product: product, show_type: false %} {% endif %} {% endfor %} </div> </div> {% endfor %} <!-- 复杂的购物车总结 --> <div class="cart-summary"> {% if cart.item_count > 0 %} {% assign subtotal = 0 %} {% assign shipping = 0 %} {% assign tax_rate = 0.08 %} {% for item in cart.items %} {% assign line_total = item.quantity | times: item.price %} {% assign subtotal = subtotal | plus: line_total %} <div class="cart-line-item"> <span class="item-title">{{ item.title }}</span> <span class="item-quantity">{{ item.quantity }}</span> <span class="item-price">{{ line_total | money }}</span> </div> {% endfor %} {% if subtotal > 50000 %} {% assign shipping = 0 %} {% else %} {% assign shipping = 800 %} {% endif %} {% assign tax = subtotal | times: tax_rate %} {% assign total = subtotal | plus: shipping | plus: tax %} <div class="cart-totals"> <div class="subtotal">小计: {{ subtotal | money }}</div> <div class="shipping">运费: {{ shipping | money }}</div> <div class="tax">税费: {{ tax | money }}</div> <div class="total">总计: {{ total | money }}</div> </div> {% else %} <div class="empty-cart"> <p>购物车是空的</p> <a href="/collections" class="continue-shopping">继续购物</a> </div> {% endif %} </div>

性能优化技巧

避免重复计算

<!-- 不好的做法 --> {% for product in collection.products %} {% if collection.products.size > 10 %} <!-- collection.products.size 在每次循环中都会计算 --> {% endif %} {% endfor %} <!-- 好的做法 --> {% assign product_count = collection.products.size %} {% for product in collection.products %} {% if product_count > 10 %} <!-- 使用预计算的值 --> {% endif %} {% endfor %}

减少嵌套深度

<!-- 不好的做法 --> {% for product in collection.products %} {% if product.available %} {% if product.price < 10000 %} {% if product.tags contains 'featured' %} <!-- 深层嵌套 --> {% endif %} {% endif %} {% endif %} {% endfor %} <!-- 好的做法 --> {% for product in collection.products %} {% unless product.available %}{% continue %}{% endunless %} {% unless product.price < 10000 %}{% continue %}{% endunless %} {% unless product.tags contains 'featured' %}{% continue %}{% endunless %} <!-- 处理符合条件的产品 --> {% endfor %}

下一步学习

掌握了标签和控制结构后,建议继续学习:

  1. 运算符和表达式 - 学习更多操作符
  2. Shopify 对象参考 - 了解可用对象
  3. 高级 Liquid 技巧 - 进阶用法
  4. 性能优化 - 优化技巧

标签是 Liquid 的核心功能,掌握它们将让您能够创建复杂而强大的模板逻辑!

最后更新时间: