macro, nested, return

概要

<#macro name param1 param2 ... paramN>
  ...
  <#nested loopvar1, loopvar2, ..., loopvarN>
  ...
  <#return>
  ...
</#macro>

这里:

  • name: 宏变量的名称,它不是表达式。和 顶层变量 的语法相同,比如 myMacromy\-macro。 然而,它可以被写成字符串的形式,如果宏名称中包含保留字符时,这是很有用的, 比如 <#macro "foo~bar">...。 注意这个字符串没有扩展插值(如 "${foo}")。
  • param1param2,等...: 局部变量 的名称,存储参数的值 (不是表达式),在 = 号后面和默认值(是表达式)是可选的。 默认值也可以是另外一个参数,比如 <#macro section title label=title>。参数名称和 顶层变量 的语法相同,所以有相同的特性和限制。
  • paramN, 最后一个参数,可能会有三个点(...), 这就意味着宏接受可变数量的参数,不匹配其它参数的参数可以作为最后一个参数 (也被称作笼统参数)。当宏被命名参数调用, paramN 将会是包含宏的所有未声明的键/值对的哈希表。当宏被位置参数调用, paramN 将是额外参数的序列。 (在宏内部,要查找参数,可以使用 myCatchAllParam?is_sequence。)
  • loopvar1loopvar2等...: 可选的,循环变量 的值, 是 nested 指令想为嵌套内容创建的。这些都是表达式。

returnnested 指令是可选的,而且可以在 <#macro ...></#macro> 之间被用在任意位置和任意次数。

没有默认值的参数必须在有默认值参数 (paramName=defaultValue) 之前。

描述

创建一个宏变量(在当前命名空间中,如果你知道命名空间的特性)。 如果你对宏和自定义指令不了解,你应该阅读 自定义指令指南

宏变量存储模板片段(称为宏定义体)可以被用作 自定义指令。 这个变量也存储自定义指令的被允许的参数名。当你将这个变量作为指令时, 你必须给所有参数赋值,除了有默认值的参数。 默认值当且仅当你调用宏而不给参数赋值时起作用。

变量会在模板开始时被创建;而不管 macro 指令放置在模板的什么位置。因此,这样也可以:

<#-- call the macro; the macro variable is already created: -->
<@test/>
...

<#-- create the macro variable: -->
<#macro test>
  Test text
</#macro>

然而,如果宏定义被插在 include 指令中, 它们直到 FreeMarker 执行 include 指令时才会可用。

例如:没有参数的宏:

<#macro test>
  Test text
</#macro>
<#-- call the macro: -->
<@test/>

将会输出:

  Test text
 

示例:有参数的宏:

<#macro test foo bar baaz>
  Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<#-- call the macro: -->
<@test foo="a" bar="b" baaz=5*5-2/>

将会输出:

  Test text, and the params: a, b, 23
   

示例:有参数和默认值参数的宏:

<#macro test foo bar="Bar" baaz=-1>
  Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<@test foo="a" bar="b" baaz=5*5-2/>
<@test foo="a" bar="b"/>
<@test foo="a" baaz=5*5-2/>
<@test foo="a"/>

将会输出:

  Test text, and the params: a, b, 23
  Test text, and the params: a, b, -1
  Test text, and the params: a, Bar, 23
  Test text, and the params: a, Bar, -1
 

示例:更为复杂的宏。

<#macro list title items>
  <p>${title?cap_first}:
  <ul>
    <#list items as x>
      <li>${x?cap_first}
    </#list>
  </ul>
</#macro>
<@list items=["mouse", "elephant", "python"] title="Animals"/>

将会输出:

  <p>Animals:
  <ul>
      <li>Mouse
      <li>Elephant
      <li>Python
  </ul>
 

示例:支持多个参数和命名参数的宏:

<#macro img src extra...>
  <img src="/context${src?html}"
  <#list extra?keys as attr>
    ${attr}="${extra[attr]?html}"
  </#list>
  >
</#macro>
<@img src="/images/test.png" width=100 height=50 alt="Test"/>

将会输出:

  <img src="/context/images/test.png"
    alt="Test"
    height="50"
    width="100"
  >

示例:支持多个位置参数的宏,不管是否使用命名或位置参数传递:

<#macro m a b ext...>
  a = ${a}
  b = ${b}
  <#if ext?is_sequence>
    <#list ext as e>
      ${e?index} = ${e}
    </#list>
  <#else>
    <#list ext?keys as k>
      ${k} = ${ext[k]}
    </#list>
  </#if>
</#macro>

<@m 1 2 3 4 5 />

<@m a=1 b=2 c=3 d=4 e=5 data\-foo=6 myns\:bar=7 />

将会输出:

  a = 1
  b = 2
      0 = 3
      1 = 4
      2 = 5

  a = 1
  b = 2
      c = 3
      d = 4
      e = 5
      data-foo=6
      myns:bar=7
Warning!

当前,命名的笼统参数是无序的,也就是说,不知道它们枚举时的顺序。 那么它们不会按相同传递顺序返回(上述示例输出相同的顺序只是为了理解)。

nested

nested 指令执行自定义指令开始和结束标签中间的模板片段。 嵌套的片段可以包含模板中任意合法的内容:插值,指令等...它在上下文环境中被执行, 也就是宏被调用的地方,而不是宏定义体的上下文中。因此,比如, 你不能看到嵌套部分的宏的局部变量。如果你没有调用 nested 指令, 自定义指令开始和结束标记中的部分将会被忽略。

比如:

<#macro do_twice>
  1. <#nested>
  2. <#nested>
</#macro>
<@do_twice>something</@do_twice>

将会输出:

  1. something
  2. something
 

nested 指令可以对嵌套内容创建循环变量。例如:

<#macro do_thrice>
  <#nested 1>
  <#nested 2>
  <#nested 3>
</#macro>
<@do_thrice ; x>
  ${x} Anything.
</@do_thrice>

将会输出:

  1 Anything.
  2 Anything.
  3 Anything.
 

更为复杂的示例:

<#macro repeat count>
  <#list 1..count as x>
    <#nested x, x/2, x==count>
  </#list>
</#macro>
<@repeat count=4 ; c, halfc, last>
  ${c}. ${halfc}<#if last> Last!</#if>
</@repeat>

将会输出:

  1. 0.5
  2. 1
  3. 1.5
  4. 2 Last!
 

return

使用 return 指令, 你可以在任意位置留下一个宏或函数定义。比如:

<#macro test>
  Test text
  <#return>
  Will not be printed.
</#macro>
<@test/>

将会输出:

  Test text