一、核心概念
在 FreeMarker 模板引擎中,<#function>
用于在模板中定义可复用的函数,类似于编程语言中的方法或函数。通过 <#function>
定义的函数可以在模板中多次调用,提高模板的可维护性和复用性。
1. <#function>
的作用
- 定义可复用的逻辑片段。
- 接收参数,执行计算或逻辑处理。
- 可以返回值(通过
<#return>
)。 - 作用域为当前模板,不能跨模板调用。
2. <#function>
与 <#macro>
的区别
特性 | <#function> |
<#macro> |
---|---|---|
是否返回值 | ✅ 是 | ❌ 否(仅输出内容) |
返回方式 | <#return value> |
直接输出内容 |
使用场景 | 逻辑计算、返回结果 | 生成 HTML 或文本片段 |
调用方式 | ${functionName(args)} |
<@macroName args... /> |
🛠️ 二、操作步骤(详细)
✅ 步骤 1:定义函数
使用 <#function>
定义一个函数,语法如下:
<#function functionName param1 param2 ...>
<#-- 函数体 -->
<#return 返回值>
</#function>
示例:定义一个加法函数
<#function add a b>
<#local sum = a + b>
<#return sum>
</#function>
✅ 步骤 2:调用函数
使用 ${functionName(args...)}
调用函数,并获取返回值。
${add(3, 5)} <#-- 输出:8 -->
✅ 步骤 3:函数参数传递
函数可以接收任意数量的参数,支持以下类型:
- 数字
- 字符串
- 布尔值
- 序列(列表)
- 哈希(Map)
- 函数(高阶函数)
示例:多参数函数
<#function formatUser name age>
<#return "姓名:${name},年龄:${age}">
</#function>
${formatUser("张三", 25)} <#-- 输出:姓名:张三,年龄:25 -->
✅ 步骤 4:使用局部变量(<#local>
)
函数中推荐使用 <#local>
定义变量,避免污染全局作用域。
<#function multiply a b>
<#local product = a * b>
<#return product>
</#function>
✅ 步骤 5:嵌套函数调用
函数可以调用其他函数。
<#function square x>
<#return multiply(x, x)>
</#function>
${square(4)} <#-- 输出:16 -->
✅ 步骤 6:处理默认参数(模拟)
FreeMarker 不支持默认参数语法,但可以通过 <#if>
判断模拟。
<#function greet name>
<#if name??>
<#return "你好,${name}!">
<#else>
<#return "你好,陌生人!">
</#if>
</#function>
${greet("李四")} <#-- 输出:你好,李四! -->
${greet()} <#-- 输出:你好,陌生人! -->
✅ 步骤 7:函数返回复杂结构(Map、List)
函数可以返回复杂结构,如 Map 或 List。
<#function getUserInfo id name age>
<#return {"id": id, "name": name, "age": age}>
</#function>
<#assign user = getUserInfo(1, "王五", 30)>
用户ID:${user.id}<br>
用户名:${user.name}<br>
年龄:${user.age}
⚠️ 三、常见错误与注意事项
❌ 错误 1:未使用 <#return>
返回值
<#function noReturn x>
<#local result = x * 2>
</#function>
${noReturn(5)} <#-- 报错:函数没有返回值 -->
解决方法: 每个函数必须有 <#return>
。
❌ 错误 2:函数名重复
<#function add a b>
<#return a + b>
</#function>
<#function add x y> <#-- 报错:函数名重复 -->
<#return x + y>
</#function>
解决方法: 函数名在模板中必须唯一。
❌ 错误 3:在 <#function>
外使用 <#return>
<#function badReturn x>
</#function>
<#return x> <#-- 报错:不在函数体内 -->
解决方法: <#return>
只能在 <#function>
块中使用。
❌ 错误 4:函数参数未传递
<#function requiredParam x>
<#return x * 2>
</#function>
${requiredParam()} <#-- 报错:参数缺失 -->
解决方法: 调用时必须传递所有参数,或在函数中判断是否为空。
🧠 四、使用技巧
1. 使用函数封装业务逻辑
<#function isAdult age>
<#return age >= 18>
</#function>
<#if isAdult(20)>
<p>已成年</p>
<#else>
<p>未成年</p>
</#if>
2. 使用函数生成 HTML 片段
<#function renderButton text color>
<#return "<button style='color:${color}'>${text}</button>">
</#function>
${renderButton("提交", "blue")}
3. 函数返回模板片段(结合 <#assign>
)
<#function getGreeting name>
<#return "欢迎 ${name} 访问我们的网站!">
</#function>
<#assign greeting = getGreeting("张三")>
<p>${greeting}</p>
4. 函数返回布尔值用于条件判断
<#function isEven x>
<#return (x % 2) == 0>
</#function>
<#if isEven(4)>
<p>是偶数</p>
<#else>
<p>是奇数</p>
</#if>
🏆 五、最佳实践
实践项 | 建议 |
---|---|
函数命名清晰 | 使用动词或名词描述函数功能,如 formatPrice , calculateTotal |
避免副作用 | 函数应只返回结果,不修改全局变量 |
保持函数单一职责 | 一个函数只做一件事 |
使用 <#local> 定义变量 |
避免污染全局作用域 |
合理使用返回值类型 | 返回值应为数字、字符串、Map、List 等结构化数据 |
封装复杂逻辑 | 将复杂判断或计算封装为函数,提高可读性 |
函数复用优先 | 重复逻辑应提取为函数,避免模板冗余 |
🔧 六、性能优化
优化项 | 说明 |
---|---|
减少函数嵌套 | 多层嵌套影响性能和可读性 |
避免频繁调用复杂函数 | 将结果缓存到变量中,避免重复计算 |
避免在循环中频繁调用函数 | 提前计算并赋值给变量 |
函数体尽量简洁 | 函数体过大影响性能,建议拆分 |
减少字符串拼接函数 | 多次拼接影响性能,建议使用 <#assign> 或 <#macro> 替代 |
📚 七、总结
维度 | 内容 |
---|---|
核心指令 | <#function> , <#return> |
函数特点 | 可返回值、可接收参数、不可跨模板调用 |
调用方式 | ${functionName(args...)} |
返回值 | 支持数字、字符串、Map、List 等 |
注意事项 | 必须有 <#return> 、函数名唯一、不可在函数外使用 <#return> |
最佳实践 | 单一职责、命名清晰、封装逻辑、使用 <#local> |
性能优化 | 减少嵌套、缓存结果、避免重复调用 |
📌 附录:函数调用示例汇总
函数定义 | 调用方式 | 返回值 |
---|---|---|
<#function add a b><#return a + b></#function> |
${add(2, 3)} |
5 |
<#function greet name><#return "你好," + name + "!"></#function> |
${greet("李四")} |
你好,李四! |
<#function isEven x><#return (x % 2) == 0></#function> |
${isEven(4)} |
true |
<#function getUser id name><#return {"id": id, "name": name}></#function> |
<#assign u = getUser(1, "王五")> |
{"id":1,"name":"王五"} |
📚 推荐阅读
📌 总结一句话:
<#function>
是 FreeMarker 中用于封装可复用逻辑的核心机制,通过合理定义与调用函数,可以显著提升模板的可维护性与复用性。但应遵循最佳实践,避免副作用和性能瓶颈,使模板逻辑清晰、高效。