本文翻译自JavaScript Template Syntax

表达式与表达式修饰符

  ${expr}
  ${expr|modifier}
  ${expr|modifier1|modifier2|...|modifierN}
  ${expr|modifier1:argExpr1_1}
  ${expr|modifier1:argExpr1_1,argExpr1_2,...,argExpr1_N}
  ${expr|modifier1:argExpr1_1,argExpr1_2|...|modifierN:argExprN_1,argExprN_2,...,argExprN_M}

这里有一份内置的修饰符列表,你也可以通过TrimPath提供的API来创建自定义的修饰符。

表达式还可以写成${% customer.firstName %}这种形式,多出的%字符允许你的表达式中出现花括号}。例如:

  Visit our ${% emitLink('Solutions and Products', 
                            { color: 'red', blink: false }) %} 

表达式中的空白字符是可选的,你也可以写成下面的格式:

  ${%customer.firstName%}
  ${%customer.firstName|capitalize%}

声明

声明标签可以嵌套使用。

控制流

  {if testExpr} 
    {elseif testExpr}
    {else}
  {/if}

示例:

  {if customer != null && customer.balance > 1000}
    We love you!
  {/if}

  {if user.karma > 100}
      Welcome to the Black Sun.
  {elseif user.isHero}
      Sir, yes sir!  Welcome!
      {if user.lastName == "Yen"}
         Fancy some apple pie, sir?
      {/if}
  {/if}
  <a href="/login{if returnURL != null && returnURL != 'main'}?goto=${returnURL}{/if}">Login</a>

TrimPath引擎还定义了一个帮助方法叫做defined(str),它可以检查给定的参数是否是JavaScript中的undefined值。通过它可以很方便的判断某个值是否被定义:

  {if defined('adminMessage')}
    System Administrator Important NOTICE: ${adminMessage}
  {/if}

循环

  {for varName in listExpr}
  {/for}


  {for varName in listExpr}
    ...循环主体...
  {forelse}
    ...当listExpr的值是null或者长度为0时执行此区域...
  {/for}

循环过程中可以访问2个额外的变量:
- __LIST__varName - 保存了listExpr的执行结果 - varName_index - 保存了循环过程中当前值对应的索引或是键名。

示例:

  {for x in customer.getRecentOrders()}
    ${x_index} : ${x.orderNumber} <br/>
  {forelse}
    You have no recent orders.
  {/for}

 以下是与上边代码功能相同的伪代码
  var __LIST__x = customer.getRecentOrders();
  if (__LIST__x != null && __LIST__x.length > 0) {
    for (var x_index in __LIST__x) {
      var x = __LIST__x[x_index];
      ${x_index} : {$x.orderNumber} <br/>
    }
  } else {
    You have no recent orders.
  }

变量声明

  {var varName}
  {var varName = varInitExpr}

示例:

 {var temp = crypto.generateRandomPrime(4096)}
  Your prime is ${temp}.  

宏声明

  {macro macroName(arg1, arg2, ...argN)}
    ...body of the macro...
  {/macro}

示例:

  {macro htmlList(list, optionalListType)}
    {var listType = optionalListType != null ? optionalListType : "ul"}
    <${listType}>
      {for item in list}     
        <li>${item}</li>
      {/for}
    </${listType}>
  {/macro}

 使用宏
  ${htmlList([ 1, 2, 3])}
  ${htmlList([ "Purple State", "Blue State", "Red State" ], "ol")}
  {var saved = htmlList([ 100, 200, 300 ])}
  ${saved} and ${saved}

默认情况下,宏只能在定义它的模板中使用。如果你想导出一个宏以便在其他模板中复用,一种方法就是把保存一份宏的引用到contentObject中(contentObject就是你调用template.process方法时传递的参数)。在调用process方法前先设置'contextObject['exported'] = {};,然后可以在末班中通过这种方法获得宏的引用:

 {macro userName(user)}
    {if user.aliasName != null && user.aliasName.length > 0}
      ${user.aliasName}
    {else}
      ${user.login}
    {/if}
  {/macro}
  ${exported.userName = userName |eat}

你也可以直接设置contextObject['exported'] = contextObject;,这样做也可以工作,但是会造成循环引用。

CDATA文本块

  {cdata}
    ...此区域内的文本不会被引擎解析...
  {/cdata}

  {cdata EOF}
    ...此区域内的文本不会被引擎解析...
  EOF

你可以使用{cdata EOF}...EOF或是{cdata}...{/cdata}这2中语法来告诉模板引擎忽略对特定文本块的处理。这些文本块会被直接输出,其中包含的任何标签都不会被解析。当你需要通过JavaScript模板生成其他JavaScript模板时会非常方便。 - EOF可以是任何不包含}的标记字符串。标记字符串用来标示一个文本块的结束。 - 文本块可以包含换行符,输出时模板引擎会保留这些换行。

示例:

Hello, ${user.firstName}.
An example of expression markup in JST looks like...
{cdata END_OF_THE_CDATA_SECTION}
 ${customer.firstName} ${customer.lastName}
END_OF_THE_CDATA_SECTION
...which shows a customer's name.

Let me repeat that...
{cdata}
 ${customer.firstName} ${customer.lastName}
{/cdata}
...will show a customer's name.

以上模板会输出以下内容:

Hello, Steve.
An example of expression markup in JST looks like...

 ${customer.firstName} ${customer.lastName}

...which shows a customer's name.

Let me repeat that...

 ${customer.firstName} ${customer.lastName}

...will show a customer's name.

嵌入的JavaScript

eval代码块

  {eval}
    ...模板引擎解析模板时将执行此区域代码...
  {/eval

  {eval EOF}
    ...模板引擎解析模板时将执行此区域代码...
  EOF

EOF可以是任何不包含}的文本。 {eval}块可以用来在模板中定义多行的JavaScript事件处理函数。例如:

  {eval} 
    sel_onchange = function() {
     ...事件处理函数定义...;
    }
  {/eval}

需要注意的是,在上边的事例中我们_没有_使用var关键字来声明变量,例如var sel_onchange = function() {...}。这是为了保证sel_onchange在全局作用域中以便可以被事件处理机制访问到。

minify块

  {minify}
    ...此处可以写多行代码,模板引擎输出时会合并成一行...
  {/minify 

  {minify EOF}
    ...此处可以写多行代码,模板引擎输出时会合并成一行...
  EOF

{minify}块允许你在HTML属性中嵌入多行的JavaScript或CSS代码。对JavaScript来说,这可以很方便的编写多行的事件处理函数。例如:

  <select onchange="{minify}
     ...复杂的多行事件处理逻辑...;
     this.enabled = false;
  {/minify}">

  <select onchange="{minify END_OF_JS}
     ...复杂的多行事件处理逻辑...;
     this.enabled = false;
  END_OF_JS">

对应CSS来说,{minify}允许你方便的嵌入多行行内样式代码,例如:

<div id="commentPanel"
     style="{minify}
              display:none; 
              margin: 1em;
              border: 1px solid #333;
              background: #eee;
              padding: 1em;
            {/minify}">
</div>