XTemplate 是富邏輯的 KISSY 模板引擎,面向復雜的業務邏輯場景,同時保持高性能和豐富的配置方法,是易學易懂的模板語言。
一個典型的XTemplate模板實例:
Hello {{name}}
You have just won ${{value}}! {{#if data}} {{#each data}} {{name}}-{{xindex}}/{{xcount}} {{/each}} {{/if}}
對應要填充的JSON:
{ name:'Kissy', value:'10000', data:[ {name:1}, {name:2} ] }
拼裝結果:
Hello Kissy You have just won $10000! 1-0/2 2-1/2
XTemplate 可以放置於HTML、配置文件、程序代碼中,核心機制就是把模板中的標簽替換為JSON對象給定的值,並同時具有一定的模板語言邏輯。 模板中除了提供最簡單的變量替換,還提供if、else和foreach等常見功能。所謂標簽,指的是雙花括號包含的一個標記,{{name}}
就是一個標簽,{{#name}}
也是一個標簽。XTemplate模板語言是抽象的,可以有多種編程語言的實現,KISSY 的xtemplate
模塊實現了 XTemplate 標記語言。
這樣來引入xtemplate模塊:
KISSY.use('xtemplate',function(S,XTemplate){ // use XTemplate });
如何通過KISSY來解析XTemplate模板?先看一個簡單的例子,實現變量替換:
KISSY.use('xtemplate', function (S, XTemplate) { var tpl = 'this is {{title}}!'; var data = { title: 'o' }; var render = new XTemplate(tpl).render(data); alert(render);// => "this is o!" });
你也可以直接離線編譯 xtemplate 為 kissy 模塊,那么線上直接引入 xtemplate/runtime 即可,還省去了在線編譯的時間,提高運行效率。
KISSY.use('xtemplate/runtime,tpls/x',function(S, XTemplate,x){ var data={z:1}; new XTemplate(x).render(data); });
KISSY XTemplate 語法
{{key}}
變量替換
使用{{key}}
輸出變量值,key
表示要替換的JSON中的key,替換為JSON中key對應的value。比如XTemplate:
this is {{title}}!
要填充的JSON對象:
{ title:'Kissy' }
拼裝結果為:
this is Kissy!
{{if condition}}
條件語句
使用{{if condition}}
來實現條件判斷,condition
表示要判斷的值,判斷是否存在、為空、是否為falsy。比如模板為:
{{#if title}} has title {{/if}} {{@if title2}} has title2 {{else}} not has title2 {{/if}}
要填充的JSON對象:
{ title:'kissy', title2:'' }
填充結果為:
has title
not has title2
其中{{#if}}
和{{@if}}
完全等價,在某些環境中(比如velocity)里#
有特殊語義,這時可以用@
作為if
前綴。
此外,title
的取值不為這些值時被認為是真值:0
,null
,''
,false
,NaN
,undefined
。當取值為空數組[]
或空對象'{}'時,則認為是真值。
{{^if condition}}
條件非語句
使用{{^if condition}}
來實現條件非,如果condition
值為空或者假值(0
, null
, ''
, false
, NaN
, undefined
),則此語句為 true。如果condition
有值且是真值,語句為 false。比如這段 XTemplate 模板:
{{^if title}} do not has title {{/if}} {{^if title2}} do not has title2 {{else}} has title2 {{/if}}
填充的JSON為:
{ title:undefined, title2:'' }
填充結果為:
do not has title do not has title2
{{#each}}
循環語句
循環對象數組
使用{{#each data}}
表示循環,data
表示循環的對象,數組類型,每個item為一個對象,比如這段 XTemplate:
{{#each data}} {{name}}-{{xindex}}/{{xcount}} {{/each}}
如果填充的JSON為數組類型:
{ data:[ {name:1}, {name:2} ] }
渲染結果為:
1-0/2
2-1/2
這時循環內的{{xindex}}
表示循環的索引值,{{xcount}}
表示循環的總次數,{{name}}
是數組中每個對象的屬性name
,替換為屬性的值
循環單數組
循環的data
為數組類型,每個item為一個值,而非對象,比如這段XTemplate:
{{#each data}} {{this}}-{{xindex}}/{{xcount}} {{/each}}
要填充的JSON對象為:
{ data:['jayli','yiminghe'] }
渲染結果為:
jayli-0/2
yiminghe-1/2
其中循環內的{{this}}
表示當前循環的item值,{{xindex}}
和{{xcount}}
含義同上
each中數據層次相對位置的訪問
循環體內可以獲取JSON對象上的其他屬性,同過相對位置寫法獲得,比如這段XTemplate:
{{#each data}} {{this}}-{{../total}} {{/each}}
要填充的JSON對象為:
{ data: [1, 2], total: 3 }
填充結果為:
1-3
2-3
其中,{{../total}}
表示從循環體內跳出到data
屬性所在的層級,去查找data
屬性的兄弟屬性total
的值。同樣,{{#each}}
可以被{{@each}}
代替。
{{#with}}
語句
類似 JavaScript 中的with
語法,with 語句是為逐級的對象訪問提供命名空間式的速寫方式。我們在 XTemplate 中增加了類似的功能。比如{{#with data}}...{{/with}}
,中間可以直接調用對象data
里的屬性,輸出對應的值。
比如這段 XTemplate
{{#with data}} {{name}}-{{age}} {{/with}}
要填充的JSON為:
{ data:{ name:'jayli', age:'2' } }
填充結果為:
jayli-2
其中{{#with}}
可以用{{@with}}
代替
支持 with 中數據層次間的相對位置訪問
同{{#each}}
一樣,with 語句中也可以用相對路徑寫法來訪問對象其他層級的屬性,比如這段模板:
{{#with data}} {{#with p}} {{name}}-{{age}}-{{../l2}}-{{../../l1}} {{/with}} {{/with}}
要填充的JSON為:
{
l1: 1,
data: {
l2: 2,
p: {
name: 'h',
age: 2
}
}
}
填充結果為:
h-2-2-1
{{!comment}}
注釋
XTemplate的注釋寫法為{{!comment}}
,其中comment為注釋內容,注釋將會被忽略。
\\{{prop}}
標簽的轉義
如果想直接輸出{{prop}}
的內容,而不想被解析為標簽,則用轉義寫法\\{{prop}}
,比如模板:
output \\{{name}} as {{name}}
要填充的JSON為:
{name:'jay'}
輸出結果為:
output {{name}} as jay
{{{prop}}}
html 標簽轉義
如果輸出的內容中包含字符<
和>
,在普通標簽{{prpp}}
中會被轉義為<
和>
,如果不想被轉義,需使用{{{prop}}}
,比如這段模板:
my {{title}} is {{{title}}}
要填充的JSON為:
{ title:'<a>' }
輸出結果為:
my <a> is <a>
用表達式作為變量
目前支持的表達式為+
,-
,*
,/
,%
。比如這段模板:
{{n+3*4/2}}
填充JSON為
{n:1}
輸出結果為:
7
關系表達式
目前支持目前支持 ===
!==
>
>=
<
<=
,比如這段模板:
{{#if n>n2+4/2}} {{n+1}} {{else}} {{n2+1}} {{/if}}
要填充的JSON:
{ n:5, n2:2 }
輸出結果為:
6
each 循環中的關系表達式
直接看例子,看這段模板:
{{#each data}}
{{#if this>../limit+1}} {{this+1}}-{{xindex+1}}-{{xcount}} {{/if}} {{/each}}
要填充的JSON
{ data: [11, 5, 12, 6, 19, 0], limit: 10 }
填充結果:
13-3-6
20-5-6
with 中的關系表達式
直接看例子,看這段模板:
{{#with data}} {{#if n>../limit/5}} {{n+1}} {{/if}} {{/with}}
填充JSON為:
{ data: { n: 5 }, limit: 10 }
輸出結果為:
6
{{set}}
設置變量
通過{{set expression}}
來設置變量的值,可以設置多個,賦值表達式之間用空格分隔,比如這段模板:
{{#each data}}
{{set n2=this*2 n3=this*3}} {{n2}}-{{n3}} {{/each}}
填充JSON:
{ data: [1, 2] }
結果為:
2-3
4-6
對 mustache 對象的兼容
XTemplate 支持對 mustache 形式的對象的兼容,比如這段模板:
{{#data}}{{name}}-{{age}}{{/data}}
填充JSON為:
{ data: { name: 'h', age: 2 } }
輸出結果為
h-2
對 mustache 數組的兼容
XTemplate 支持對 mustache 形式的數組的兼容,比如這段模板:
{{#data}} {{name}}-{{xindex}}/{{xcount}} {{/data}}
填充JSON:
{ data: [ {name: 1}, {name: 2} ] }
輸出結果為:
1-0/2
2-1/2
KISSY XTemplate 附加功能
以上語法可以在不同語言中實現,在 JavaScript 環境中得益於 JS 語言的動態性,KISSY 為 XTemplate 提供了更多的瀏覽器端的渲染策略和工具。這些功能只在 JavaScript 的實現中可用, 如果你的模板可同時被JavaScript渲染也會被其他語言渲染(比如在后台被Java渲染),請盡可能避免這種用法。
全局行內單個標簽擴展
如果我想擴展 XTemplate 中的標簽個數,需要自定義擴展標簽,使用XTemplate.addCommand()
實現全局行內命令擴展,比如這樣一段擴展(自定義一個單個標簽,無配對出現):
XTemplate.addCommand('global', function (scopes, option) { return 'global-' + option.params[0]; });
這樣這段模板就可以渲染出來:
my {{global title}}
如果JSON為{title:'1'}
,那么渲染結果為:
my global-1
全局塊狀標簽擴展
除了擴展單個標簽,還可以擴展塊狀標簽,例子:
XTemplate.addCommand('global', function (scopes, option) { return 'global-' + option.fn(scopes); });
對於這段模板就可以被識別:
{{#global}} {{title}} {{/global}}
如果JSON對象為{title:1}
,渲染結果為:
global-1
刪除全局標簽的定義
用removeCommand()
方法來刪除自定義的全局標簽,調用格式為:XTemplate.removeCommand(commandName,fn)
。
局部行內標簽擴展
如果要把標簽擴展不做成全局,可以臨時定義針對一段模板的標簽擴展,做法是在XTemplage()
函數中傳入第二個配置參數:
var render = new XTemplate(tpl, { commands: { 'global': function (scopes, option) { return 'global-' + option.params[0]; } } }).render(data);
局部塊狀標簽擴展
類似行內標簽擴展,塊狀標簽擴展需要用option.fn(scopes)
來激活,參照上文,做法是:
var render = new XTemplate(tpl, { commands: { 'global': function (scopes, option) { return 'global-' + option.fn(scopes); } } }).render(data);
局部后綴名判斷標簽擴展
參照標簽的擴展規則,再來看一個更復雜的例子,我們可以自定義條件判斷的規則:
var render = new XTemplate(tpl, { commands: { 'endsWith': function (scopes, option) { return S.endsWith(option.params[0], option.params[1]) ? option.fn(scopes) : ''; } } }).render(data);
這里擴展了自定義標簽endsWith
,對於這段模板:
{{d}} ends with {{#endsWith d "jpg"}}jpg{{/endsWith}} {{#endsWith d "gif"}}gif{{/endsWith}}
JSON對象為{d:'x.jpg'}
,輸出結果為:
x.jpg ends with jpg
下載地址:https://www.npmjs.org/package/xtemplate