Liquid 语法详解
Liquid 是一种安全、易学的模板语言,本指南将深入介绍 Liquid 的语法规则、标记类型和高级用法。
语法基础
Liquid 标记类型
Liquid 有三种主要的标记类型:
<!-- 1. 输出标记 - 输出内容 -->
{{ variable }}
 
<!-- 2. 逻辑标记 - 创建逻辑 -->
{% if condition %}
{% endif %}
 
<!-- 3. 注释标记 - 添加注释 -->
{% comment %}这是注释{% endcomment %}空白控制
使用连字符 - 来控制输出中的空白:
<!-- 标准输出 -->
{{ product.title }}
{{ product.price }}
 
<!-- 控制空白 -->
{{- product.title -}}
{{- product.price -}}
 
<!-- 在标签中控制空白 -->
{%- if product.available -%}
  有库存
{%- endif -%}示例对比:
<!-- 带空白 -->
<ul>
  {% for item in cart.items %}
    <li>{{ item.title }}</li>
  {% endfor %}
</ul>
 
<!-- 控制空白 -->
<ul>
  {%- for item in cart.items -%}
    <li>{{ item.title }}</li>
  {%- endfor -%}
</ul>变量和赋值
基本变量赋值
<!-- 简单赋值 -->
{% assign product_title = product.title %}
{% assign sale_price = product.price | times: 0.8 %}
 
<!-- 字符串赋值 -->
{% assign greeting = "欢迎来到我们的商店" %}
{% assign css_class = "product-card featured" %}
 
<!-- 使用变量 -->
<h1>{{ product_title }}</h1>
<p class="{{ css_class }}">特价: {{ sale_price | money }}</p>捕获变量
使用 capture 标签创建复杂的变量:
<!-- 捕获 HTML 内容 -->
{% capture product_badge %}
  {% if product.compare_at_price > product.price %}
    <span class="sale-badge">促销</span>
  {% elsif product.tags contains 'new' %}
    <span class="new-badge">新品</span>
  {% endif %}
{% endcapture %}
 
<!-- 捕获计算结果 -->
{% capture discount_text %}
  {% assign discount = product.compare_at_price | minus: product.price %}
  {% assign discount_percent = discount | times: 100 | divided_by: product.compare_at_price | round %}
  节省 {{ discount | money }} ({{ discount_percent }}%)
{% endcapture %}
 
<!-- 使用捕获的变量 -->
<div class="product-info">
  {{ product_badge }}
  {{ discount_text }}
</div>数据类型
字符串
<!-- 字符串字面量 -->
{% assign message = "Hello World" %}
{% assign single_quotes = 'Hello World' %}
 
<!-- 字符串连接 -->
{% assign full_name = customer.first_name | append: ' ' | append: customer.last_name %}
 
<!-- 字符串包含检查 -->
{% if product.title contains "iPhone" %}
  <span class="apple-product">Apple 产品</span>
{% endif %}数字
<!-- 整数 -->
{% assign quantity = 5 %}
{% assign max_items = 10 %}
 
<!-- 浮点数 -->
{% assign discount_rate = 0.15 %}
{% assign tax_rate = 0.08 %}
 
<!-- 数字运算 -->
{% assign total = quantity | times: product.price %}
{% assign discounted_price = product.price | times: discount_rate %}布尔值
<!-- 布尔字面量 -->
{% assign is_sale = true %}
{% assign hide_price = false %}
 
<!-- 布尔表达式 -->
{% assign is_available = product.available %}
{% assign has_variants = product.variants.size > 1 %}
{% assign is_featured = product.tags contains "featured" %}数组
<!-- 数组访问 -->
{% assign first_image = product.images[0] %}
{% assign last_image = product.images.last %}
 
<!-- 数组操作 -->
{% assign sorted_products = collection.products | sort: 'title' %}
{% assign featured_products = collection.products | where: 'featured', true %}
 
<!-- 数组创建 -->
{% assign color_options = "红色,蓝色,绿色" | split: "," %}对象
<!-- 对象属性访问 -->
{{ product.title }}
{{ product['title'] }}
{{ product.variants[0].price }}
 
<!-- 嵌套对象访问 -->
{{ product.selected_or_first_available_variant.title }}
{{ customer.default_address.city }}
{{ blog.articles.first.author }}操作符
比较操作符
<!-- 相等比较 -->
{% if product.price == 100 %}
  特价商品
{% endif %}
 
{% if customer.email != blank %}
  已登录用户
{% endif %}
 
<!-- 大小比较 -->
{% if product.price > 50 %}
  高价商品
{% elsif product.price < 20 %}
  低价商品
{% else %}
  中等价位
{% endif %}
 
<!-- 包含检查 -->
{% if product.tags contains "sale" %}
  促销商品
{% endif %}逻辑操作符
<!-- AND 操作 -->
{% if product.available and product.price < 100 %}
  便宜且有库存
{% endif %}
 
<!-- OR 操作 -->
{% if product.tags contains "featured" or product.tags contains "bestseller" %}
  推荐商品
{% endif %}
 
<!-- 组合逻辑 -->
{% if product.available and (product.price < 50 or product.tags contains "sale") %}
  优惠商品
{% endif %}存在性检查
<!-- 检查是否存在 -->
{% if product.description %}
  <p>{{ product.description }}</p>
{% endif %}
 
<!-- 检查是否为空 -->
{% if product.description != blank %}
  <p>{{ product.description }}</p>
{% endif %}
 
{% unless product.description == blank %}
  <p>{{ product.description }}</p>
{% endunless %}条件语句
if/elsif/else
<!-- 基本条件 -->
{% if product.available %}
  <button type="submit">加入购物车</button>
{% else %}
  <button disabled>缺货</button>
{% endif %}
 
<!-- 多重条件 -->
{% if product.price > 100 %}
  <span class="high-price">高端商品</span>
{% elsif product.price > 50 %}
  <span class="medium-price">中档商品</span>
{% else %}
  <span class="low-price">经济实惠</span>
{% endif %}
 
<!-- 复杂条件 -->
{% if product.available %}
  {% if product.variants.size > 1 %}
    <select name="id">
      {% for variant in product.variants %}
        <option value="{{ variant.id }}">{{ variant.title }}</option>
      {% endfor %}
    </select>
  {% else %}
    <input type="hidden" name="id" value="{{ product.first_available_variant.id }}">
  {% endif %}
  <button type="submit">加入购物车</button>
{% endif %}unless
<!-- unless 语句 -->
{% unless product.available %}
  <p class="out-of-stock">商品缺货</p>
{% endunless %}
 
<!-- 等同于 -->
{% if product.available == false %}
  <p class="out-of-stock">商品缺货</p>
{% endif %}case/when
<!-- case 语句 -->
{% case product.type %}
  {% when 'Electronics' %}
    <span class="icon-electronics">📱</span>
  {% when 'Clothing' %}
    <span class="icon-clothing">👕</span>
  {% when 'Books' %}
    <span class="icon-books">📚</span>
  {% else %}
    <span class="icon-other">🎁</span>
{% endcase %}
 
<!-- 多值匹配 -->
{% case product.vendor %}
  {% when 'Apple', 'Samsung', 'Google' %}
    <span class="tech-brand">科技品牌</span>
  {% when 'Nike', 'Adidas', 'Puma' %}
    <span class="sports-brand">运动品牌</span>
  {% else %}
    <span class="other-brand">其他品牌</span>
{% 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 %}
  <div class="product-item product-{{ forloop.index }}">
    <span class="position">第 {{ forloop.index }} 位</span>
    <h3>{{ product.title }}</h3>
  </div>
{% endfor %}
 
<!-- 限制循环次数 -->
{% for product in collection.products limit: 4 %}
  <div class="featured-product">{{ product.title }}</div>
{% endfor %}
 
<!-- 跳过元素 -->
{% for product in collection.products offset: 2 limit: 4 %}
  <div class="product">{{ product.title }}</div>
{% endfor %}forloop 对象
{% for item in cart.items %}
  <tr class="cart-item">
    <td>{{ forloop.index }}</td>  <!-- 当前索引 (1开始) -->
    <td>{{ item.title }}</td>
    <td>
      {% if forloop.first %}
        第一个商品
      {% elsif forloop.last %}
        最后一个商品
      {% endif %}
    </td>
    <td>{{ forloop.length }}</td>  <!-- 总数量 -->
    <td>{{ forloop.rindex }}</td>  <!-- 反向索引 -->
  </tr>
{% endfor %}循环控制
<!-- continue - 跳过当前迭代 -->
{% for product in collection.products %}
  {% unless product.available %}
    {% continue %}
  {% endunless %}
  
  <div class="available-product">
    {{ product.title }}
  </div>
{% endfor %}
 
<!-- break - 退出循环 -->
{% for product in collection.products %}
  {% if forloop.index > 5 %}
    {% break %}
  {% endif %}
  
  <div class="top-product">
    {{ product.title }}
  </div>
{% endfor %}else 子句
<!-- 循环为空时的处理 -->
{% for product in collection.products %}
  <div class="product">{{ product.title }}</div>
{% else %}
  <p>此集合暂无商品</p>
{% endfor %}范围循环
<!-- 数字范围 -->
{% for i in (1..5) %}
  <span class="rating-star">⭐</span>
{% endfor %}
 
<!-- 变量范围 -->
{% assign max_pages = paginate.pages %}
{% for i in (1..max_pages) %}
  <a href="{{ blog.url }}?page={{ i }}" 
     {% if i == paginate.current_page %}class="current"{% endif %}>
    {{ i }}
  </a>
{% endfor %}包含和渲染
render 标签
<!-- 基本渲染 -->
{% render 'product-card' %}
 
<!-- 传递变量 -->
{% render 'product-card', product: product %}
 
<!-- 传递多个变量 -->
{% render 'product-card', 
    product: product, 
    show_vendor: true, 
    css_class: 'featured' %}
 
<!-- 在循环中渲染 -->
{% for product in collection.products %}
  {% render 'product-card', product: product %}
{% endfor %}include 标签 (已废弃)
<!-- 旧式包含 (不推荐) -->
{% include 'product-card' %}
 
<!-- 应该使用 render 代替 -->
{% render 'product-card' %}注释
单行注释
{% # 这是单行注释 %}
 
{% assign price = product.price %} {% # 获取价格 %}多行注释
{% comment %}
这是多行注释
可以包含多行内容
不会在输出中显示
{% endcomment %}
 
{% comment %}
TODO: 优化这个section的性能
- 减少循环次数
- 使用更高效的过滤器
{% endcomment %}HTML 注释
<!-- 这是 HTML 注释,会出现在输出中 -->
 
<!-- 调试信息: {{ product.id }} -->原始内容
raw 标签
<!-- 阻止 Liquid 处理内容 -->
{% raw %}
  这里的 {{ product.title }} 不会被处理
  {% if true %} 这也不会被处理 {% endif %}
{% endraw %}
 
<!-- 用于显示 Liquid 代码示例 -->
{% raw %}
  <p>使用方法: {{ product.title | upcase }}</p>
{% endraw %}液体对象作用域
全局作用域
<!-- 这些变量在整个模板中可用 -->
{{ shop.name }}
{{ cart.item_count }}
{{ customer.first_name }}局部作用域
<!-- assign 创建的变量在当前模板中可用 -->
{% assign local_var = "局部变量" %}
 
<!-- for 循环变量只在循环内可用 -->
{% for product in collection.products %}
  <!-- product 只在这个循环内可用 -->
  {{ product.title }}
{% endfor %}snippet 作用域
<!-- snippets/my-snippet.liquid -->
<!-- snippet 内的变量不会污染父作用域 -->
{% assign snippet_var = "只在snippet内可用" %}
 
<!-- 通过 render 传递的变量 -->
<div class="product-card">
  {{ product.title }}  <!-- 从外部传入 -->
</div>错误处理
安全导航
<!-- 安全访问可能不存在的属性 -->
{{ product.featured_image.alt | default: product.title }}
 
<!-- 检查对象是否存在 -->
{% if product.featured_image %}
  <img src="{{ product.featured_image | img_url: '300x300' }}" 
       alt="{{ product.featured_image.alt | escape }}">
{% endif %}默认值处理
<!-- 使用 default 过滤器 -->
{{ product.description | default: "暂无描述" }}
{{ customer.first_name | default: "访客" }}
 
<!-- 使用 or 操作符 -->
{% assign display_name = customer.first_name | default: "访客" %}性能最佳实践
避免重复计算
<!-- 好的做法 -->
{% assign available_products = collection.products | where: 'available', true %}
{% for product in available_products %}
  {{ product.title }}
{% endfor %}
 
<!-- 避免的做法 -->
{% for product in collection.products %}
  {% if product.available %}
    {{ product.title }}
  {% endif %}
{% endfor %}合理使用过滤器
<!-- 在循环外预处理 -->
{% assign sorted_tags = product.tags | sort %}
{% for tag in sorted_tags %}
  <span class="tag">{{ tag }}</span>
{% endfor %}
 
<!-- 避免重复的字符串操作 -->
{% assign base_url = shop.url | append: "/products/" %}
{% for product in collection.products %}
  <a href="{{ base_url }}{{ product.handle }}">{{ product.title }}</a>
{% endfor %}调试技巧
输出调试信息
<!-- 查看变量内容 -->
<pre>{{ product | json }}</pre>
 
<!-- 查看变量类型 -->
{{ product.price.class }}
 
<!-- 条件调试 -->
{% if settings.debug_mode %}
  <div class="debug">
    <p>Product ID: {{ product.id }}</p>
    <p>Available: {{ product.available }}</p>
    <p>Price: {{ product.price }}</p>
  </div>
{% endif %}性能监控
<!-- 记录处理时间 -->
{% assign start_time = 'now' | date: '%s' %}
 
<!-- 复杂操作 -->
{% for product in collection.products %}
  <!-- 处理产品 -->
{% endfor %}
 
{% assign end_time = 'now' | date: '%s' %}
{% assign processing_time = end_time | minus: start_time %}
 
{% if settings.debug_mode %}
  <p>处理时间: {{ processing_time }}秒</p>
{% endif %}下一步学习
掌握了 Liquid 语法后,建议继续学习:
- 变量和对象 - 深入了解变量使用
 - 过滤器完全指南 - 掌握数据处理
 - 标签和控制结构 - 学习高级标签
 - Shopify 对象参考 - 了解特定对象
 
通过理解这些语法规则,您将能够创建更加复杂和强大的 Shopify 主题!
最后更新时间: