如何玩转Handlebars.js块表达式:循环渲染列表与条件分支的终极指南
2026/9/18 6:22:41 网站建设 项目流程

如何玩转Handlebars.js块表达式:循环渲染列表与条件分支的终极指南

【免费下载链接】handlebars.jsMinimal templating on steroids.项目地址: https://gitcode.com/gh_mirrors/ha/handlebars.js

Handlebars.js 是一款流行的 JavaScript 模板引擎,而**块表达式(Block Expressions)**正是它区别于普通 Mustache 模板的核心超能力:用#each循环渲染列表、用#if做条件分支、用#with切换上下文。本文面向新手,用最少代码带你一次性掌握这三大利器。

一、什么是块表达式:比 Mustache 多出来的能力

在 Mustache 里,{{#list}}这种"节"只是隐式的遍历;而在 Handlebars.js 中,同一个语法变成了可调用的块级辅助函数(Block Helper)——你可以显式控制循环逻辑、条件判断和上下文切换,还能自定义任意行为。

官方说明:块表达式与 Mustache 节语法相同,但遇到重名时辅助函数优先。详见 README.md。

基本长这样:

<ul> {{#each products}} <li>{{name}}</li> {{/each}} </ul>

二、#each 块表达式:快速实现列表循环渲染

#each是最常用的块表达式,负责遍历数组并逐项渲染。内置实现见 each.js。

1. 基础循环:一行搞定列表

{{#each kids}} <p>{{name}} is {{age}}</p> {{/each}}

配合数据{ kids: [{name: 'Jimmy', age: 12}, {name: 'Sally', age: 4}] },即可渲染出两个<p>列表项。

2. 内置变量:循环中的"小秘书"

源码中可以看到,每次迭代都会向上下文注入indexkeyfirstlast等数据(each.js),在模板里用@前缀即可取用:

内置变量含义
@index当前项的下标(从 0 开始)
@key当前项的键名
@first是否为第一项
@last是否为最后一项
{{#each users}} <li>{{@index}}. {{this}}</li> {{/each}}

3. 遍历对象而不只是数组

#each不只认数组:普通对象会按键名逐个遍历(each.js),此时@key是对象的属性名,非常适合渲染键值对表单。

4. 空数据的 else 分支

当列表为空时,#each会执行else分支(即inverse),这是做"暂无数据"提示的标准姿势:

{{#each orders}} <tr><td>{{product}}</td></tr> {{else}} <p>暂无订单 📭</p> {{/each}}

三、#if 与 #unless:条件分支精准控制渲染

#if块表达式负责"有则渲染、无则隐藏",实现逻辑在 if.js。

1. 真值判断规则

  • 值为真值且非空时,渲染块内内容;
  • 否则执行else分支。
{{#if isLoggedIn}} <span>欢迎回来,{{name}}</span> {{else}} <a href="#">请先登录</a> {{/if}}

2. 小心数字 0:includeZero 选项

0默认被视为"空",会走 else 分支。如果希望0也走正面分支(比如渲染库存数量),加上includeZero参数即可,源码中的判断逻辑见 if.js:

{{#if stock includeZero}} 库存:{{stock}} 件 {{/if}}

3. #unless:反过来的 if

#unless就是#if的镜像,条件为假时才渲染块内内容(if.js),写法更直白:

{{#unless isVip}} <button>开通会员</button> {{/unless}}

四、#with 块表达式:切换上下文更优雅

#with会把"当前上下文"临时换成指定对象,块内直接用属性名即可,省去一层{{user.name}}式的路径。实现见 with.js:

{{#with profile}} <h1>{{name}}</h1> <p>{{bio}}</p> {{else}} <p>还没有资料</p> {{/with}}

上下文为空时同样支持else分支,非常适合"资料卡"这类可选模块。

五、组合实战:列表 + 条件 + 上下文一气呵成

真实页面往往是三者叠加,例如渲染订单列表并高亮新订单:

{{#each orders}} {{#with .}} <div class="order {{#if isNew}}new{{/if}}"> {{#each items}} <span>{{name}} ×{{qty}}</span> {{/each}} </div> {{/with}} {{else}} <p>暂无订单</p> {{/each}}

嵌套块表达式在测试用例中已被充分验证,参考 spec/blocks.js 中的{{#each person}}{{#with .}}...组合写法。

六、常见坑与避坑清单

  1. 块名未注册会"静默降级":如果{{#foo}}对应的辅助函数不存在,Handlebars 会回退到 Mustache 式的隐式遍历(block-helper-missing.js),排查"为什么没报错但输出不对"时优先检查这一点。
  2. 0 与空字符串会被判空:需要渲染0时记得加includeZero
  3. {{后不能有空格{{ #each是非法的,#必须紧跟左花括号,这是 Handlebars 与 Mustache 的一个语法差异(见 README.md)。
  4. 所有默认辅助函数集中注册eachifunlesswithloglookup等统一在 helpers.js 中注册,自定义辅助函数也可用同样的registerHelper机制扩展。

七、源码导航:按需深入

  • 循环渲染:lib/handlebars/helpers/each.js
  • 条件分支:lib/handlebars/helpers/if.js
  • 上下文切换:lib/handlebars/helpers/with.js
  • 辅助函数注册入口:lib/handlebars/helpers.js
  • 块表达式行为测试:spec/blocks.js
  • 编译器 API 文档:docs/compiler-api.md

掌握#each#if#with这三件套,就基本覆盖了 Handlebars.js 模板中 90% 的列表与分支场景。动手改改上面的示例、看看spec/blocks.js里的真实断言,你会对块表达式有更扎实的体感。🚀

【免费下载链接】handlebars.jsMinimal templating on steroids.项目地址: https://gitcode.com/gh_mirrors/ha/handlebars.js

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询