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 主题!
最后更新时间: