概述
我們在使用JS渲染DOM時,一般使用字串建立DOM然後附加到父元素上,如果附加的DOM是動態易變的,那需要在函數中寫大量邏輯。如果在控制項實現過程中,這帶來的問題更為嚴重。
解決這個問題的常見解決方案是是使用模板,作為配置項傳入控制項,實現資料和渲染的分離。具體的實現方法有以下方法:
- 字串替換,使用正則匹配將資料替換進字串中。
- 渲染函數,函數返回字串。
- 模板引擎,可以將執行字串中的函數(內建或者自訂的)
替換(Substitute)
字串替換是最簡單的實現模板的方式,看一下具體的實現:
1. 定義替換函數
複製代碼 代碼如下:
/**
* 替換字串中的欄位.
* @param {String} str 模版字串
* @param {Object} o json data
* @param {RegExp} [regexp] 匹配字串的Regex
*/
function substitute(str,o,regexp){
return str.replace(regexp || /\\?\{([^{}]+)\}/g, function (match, name) {
return (o[name] === undefined) ? '' : o[name];
});
}
2.使用配置項:
複製代碼 代碼如下:
var config = {
data : {value : '123',text:'abc'},
template : '<label>{text}</label><input type="text" value="{value}"/>'
};
3. 在建立DOM的過程中我們這樣調用:
複製代碼 代碼如下:
var str = substitute(template,data);
$(str).appendTo('body');
通過以上樣本,我們就完成了資料和字串的解耦,可以靈活的用在控制項中,當前大多數JS架構都提供了此種方式的模板。
在此基礎上可以有下面的擴充,感興趣的可以自己去實現:
1. 使用數字代替參數名:
如 '<label>{0}</label><input type="text" value="{1}"/>'
2. 嵌套使用對象屬性:
如 '<label>{obj.name}</label><input type="text" value="{obj.value}"/>'
優點:實現簡單,易於理解。
缺點:只能進行簡單的資料結構,無法處理迴圈、條件陳述式。
渲染方法(Render)
我們可以在渲染函數中處理非常複雜的邏輯,可以將渲染函數作為參數傳入配置項。
配置項:
複製代碼 代碼如下:
var config = {
data : [{value : '0',text:'abc'},{value : '1',text:'bcd'}],
renderer : function(obj){
if(obj.value === '0'){
return obj.text;
}else{
return '<img title="' + obj.text + '" src=""/>';
}
}
};
在使用時:
複製代碼 代碼如下:
for(var i = 0 ; i< data.length; i++){
var obj = data[i],
str = config.renderer(obj);
$(str).appendTo('body');
}
在處理迴圈,條件陳述式時,這是一種很好的解決方案。
優點:實現相對簡單,實現靈活,能滿足複雜資料結構,易於調試
缺點:
- 渲染函數作為配置項,不易理解。
- 函數較長時,使配置項臃腫。
- 每個情境都需要自己實現渲染函數。
模板引擎(XTemplate)
每一個JS UI庫都會有一個功能強大的模板引擎,一個模板引擎需要實現以下功能:
1. 字串替換
2. 處理複雜語句 條件、迴圈
3. 使用內嵌函數
4. 允許使用者傳入自訂函數
目前的模板引擎有2種常見的實現方式:
1. 使用正則分析字串,執行其中的特殊語句邏輯,替換對應的資料
我們來看一下KISSY 模板的一個執行個體:
'Hello, {{#each users}}{{#if _ks_value.show}}{{_ks_value.name}}{{/if}}{{/each}}.'
上面這是一個模板,可以處理迴圈、條件陳述式。
2. 對字串進行文法分析,產生文法樹,執行替換對應的標籤或資料。
下面是Ext的 xtemplate使用方式:
複製代碼 代碼如下:
var tpl = new Ext.XTemplate(
'<p>{name}\'s favorite beverages:</p>',
'<tpl for="drinks">',
'<div> - {.}</div>',
'</tpl>'
);
tpl.overwrite(panel.body, data);
優點:功能強大,靈活性高
缺點:使用複雜,更加不易理解。不便於調試。
問題思考
1. 控制項中使用模板,可以將資料和DOM分離,但是如果一個控制項中包含大量的模板,會增加使用者的工作量,而且不易於調試,需要權衡使用。
2. 如果大量控制項使用相同的模板,和相同的資料結構,每個控制項單獨配置不便於使用,更好的方案是允許父控制項配置模板。