Handlebars 简介

Handlebars 自定义 Helpers:扩展模板能力

学会注册和使用自定义 Helper,处理模板中不适合写复杂逻辑的场景,如格式化、比较运算等。

🎯 引言

学会这篇文章,你将掌握 Handlebars 的 自定义 Helper。Handlebars 的模板里不能写复杂表达式,但现实世界常有格式化、判断、计算等需求。通过 Helper,你可以把这些逻辑封装成可复用的函数,在模板里像调用 API 一样使用。


🧱 为什么需要自定义 Helper

来看一个常见需求:把价格格式化成“¥xx.xx”。

模板里不能写 {{price.toFixed(2)}},因为 Handlebars 不支持这种表达式。解决方案是写一个 Helper:

index.js
Handlebars.registerHelper('formatPrice', function (price) {
    return '¥' + price.toFixed(2);
});

模板里这样用:

<p>价格:{{formatPrice price}}</p>

传入 { price: 19.9 },输出:

<p>价格:¥19.90</p>
Helper 把“不适合放在模板里的逻辑”移到 JavaScript 中,既保持了模板清晰,又解决了实际需求。

✨ 注册一个简单的 Helper

index.js
const Handlebars = require('handlebars');

// 注册 Helper
Handlebars.registerHelper('uppercase', function (str) {
    return str.toUpperCase();
});

// 使用 Helper
const template = '<p>{{uppercase name}}</p>';
const compiled = Handlebars.compile(template);
const html = compiled({ name: 'hello' });

console.log(html);

输出:

<p>HELLO</p>

Helper 的第一个参数是模板中传入的值,后面可以继续接更多参数。


💡 带多个参数的 Helper

index.js
Handlebars.registerHelper('join', function (arr, separator) {
    return arr.join(separator);
});

模板:

<p>标签:{{join tags "、"}}</p>

传入:

{ tags: ['前端', 'Handlebars', '模板引擎'] }

输出:

<p>标签:前端、Handlebars、模板引擎</p>
Helper 函数里可以使用任意 JavaScript 逻辑,包括调用其他库、处理日期、格式化文本等。

⚖️ 实现比较运算 Helper

Handlebars 原生的 if 不支持表达式,我们可以写一个 eq Helper 来判断是否相等:

index.js
Handlebars.registerHelper('eq', function (a, b) {
    return a === b;
});

模板:

{{#if (eq status "success")}}
    <p>操作成功</p>
{{/if}}

传入:

{ status: 'success' }

输出:

<p>操作成功</p>
用括号 () 包裹 Helper 调用,可以把结果作为另一个 Helper(如 if)的参数。

🛠 常用的自定义 Helper 示例

1. 格式化日期

index.js
Handlebars.registerHelper('formatDate', function (date) {
    const d = new Date(date);
    return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
});

2. 判断数组是否为空

index.js
Handlebars.registerHelper('isEmpty', function (arr) {
    return !arr || arr.length === 0;
});

3. 计算索引加一

index.js
Handlebars.registerHelper('addOne', function (index) {
    return index + 1;
});

模板:

<ul>
    {{#each list}}
        <li>{{addOne @index}}. {{this}}</li>
    {{/each}}
</ul>

🪤 Helper 里要注意的 this

在 Helper 函数里,this 指向当前模板上下文。如果在块级 Helper 里使用,要注意上下文变化。

index.js
Handlebars.registerHelper('showContext', function () {
    console.log(this);
});

一般情况下,简单 Helper 不会用到 this,了解即可。


🧾 小节总结

  • 自定义 Helper 用于扩展模板能力,处理格式化、比较、计算等逻辑。
  • 使用 Handlebars.registerHelper() 注册 Helper。
  • Helper 可以接受一个或多个参数。
  • () 可以把 Helper 结果作为另一个 Helper 的参数。

❓ 知识问答

Q1:Handlebars 模板里能写 {{a + b}} 吗?

A:不能。Handlebars 不支持表达式,需要用自定义 Helper 实现,比如 {{add a b}}

Q2:Helper 和 Partial 有什么区别?

A:Helper 是一段 JavaScript 逻辑,返回一个值;Partial 是一段模板片段,返回一段 HTML。Helper 处理数据,Partial 复用结构。

Q3:自定义 Helper 可以返回 HTML 吗?

A:可以,但返回的字符串默认会被转义。如果想输出原始 HTML,需要用 new Handlebars.SafeString(html) 包裹。

Q4:Helper 命名有什么规范吗?

A:建议用驼峰命名,避免和内置 Helper 重名,比如不要用 ifeach 等内置名称。


🧪 小练习

请编写一个 formatDate Helper,并渲染以下数据:

index.js
const data = {
    createdAt: '2024-10-01T08:00:00.000Z'
};

// 请在这里注册 formatDate Helper
// 要求:把日期格式化为 YYYY-MM-DD

🎉 恭喜你掌握了 Handlebars 的自定义 Helper!下一篇我们会学习预编译和运行时,了解如何在生产环境中更高效地使用 Handlebars。