簡単なJavaScriptのテンプレートエンジン
5693 ワード
比較的簡単です.直接コードを貼りましょう.
モデルをコンパイルしても、コンパイルした後のモデルは実際には一つのfunctionです.このfunctionはデータパラメータを受信します.以下は例です.
(function (global) {
var _version = '1.0.0',
_setting = {
openTag: '<#', /* */
closeTag: '#>', /* */
maskOpenTag: '<!-', /* */
maskCloseTag: '-!>' /* */
},
_templateCache = {},
_escapeHTML = function (str) {
if (typeof str === 'string') {
var reg = /&(?!#?\w+;)|<|>|"|'|\//g,
rules = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/' };
return str.replace(reg, function (m) { return rules[m]; });
}
return str;
},
_compile = function (source, key) {
if (typeof key != 'undefined' && typeof _templateCache[key] === 'function') {
return _templateCache[key];
}
var code = (function () {/* */
var arr = (source || '').split(_setting.maskOpenTag);
arrayEach(arr, function (i, o) {
var _arr = o.split(_setting.maskCloseTag);
this[i] = _arr.length == 1 ?
(i == 0 ? _arr[0] : _setting.maskOpenTag + _arr[0]) : _arr[1];
});
return arr.join('');
})();
return _templateCache[key] = (function () {
var codeArr = code.split(_setting.openTag),
funArr = [
'var $T = arguments[0];
',
'var $data = this || { };
',
'var $escapeHTML = $T.escapeHTML;
',
'var $htmlArr = [];
',
'var $write = function() { Array.prototype.push.apply($htmlArr, arguments); };
'];
arrayEach(codeArr, function (i, o) {
var arr = o.split(_setting.closeTag);
if (arr.length == 1) {
funArr.push(html(arr[0]));
} else {
funArr.push(logic(arr[0]), html(arr[1]));
}
});
funArr.push('return $htmlArr.join("");');
try {
var fun = new Function(funArr.join(''));
} catch (e) {
var fun = new Function('return "Template Error !"');
}
return function () {
try {
return Function.prototype.call.apply(fun, [arguments[0], _t]);
} catch (e) {
return e.name + ' : ' + e.message;
}
};
})();
function arrayEach(arr, fun) {
if (Object.prototype.toString.call(arr) === '[object Array]') {
if (typeof fun === 'function') {
for (var i = 0, len = arr.length; i < len; i++) {
Function.prototype.call.apply(fun, [arr, i, arr[i]]);
}
}
}
}
function html(code) {
code = code
.replace(/"/g, '\\"')
.replace(/\r/g, '\\r')
.replace(/
/g, '\
');
return '$write("' + code + '");
';
}
function logic(code) {
code = code.replace(/^\s+/g, '');
if (code.indexOf('==') === 0) {
return '$write(' + code.substring(2) + ');
';
} else if (code.indexOf('=') === 0) {
return '$write($escapeHTML(' + code.substring(1) + '));
';
} else {
return code + '
';
}
}
},
_t = {
version: _version,
setting: _setting,
templateCache: _templateCache,
escapeHTML: _escapeHTML,
compile: _compile
};
global.T = global.T || {};
for (var it in _t) { global.T[it] = _t[it]; }
})(this);
原理は簡単です.つまり、テンプレート文字列を読み取り、文字列のsplitで文字列を分解して解析処理し、最終的に一つのjavascriptメソッドコードを生成し、new Functionでfunctionを作成します.モデルをコンパイルしても、コンパイルした後のモデルは実際には一つのfunctionです.このfunctionはデータパラメータを受信します.以下は例です.
<script id="t_tmp" type="text/template">
<# if (Object.prototype.toString.call(this) === '[object Array]') { #>
<table>
<# for(var i = 0; i < this.length; i++) { #>
<tr>
<td><#= this[i]['name'] #></td>
<td><#= this[i]['age'] #></td>
</tr>
<# } #>
</table>
<# } #>
</script>
var data = [
{ name: 'xiaoming', age: 23 },
{ name: 'xiaohong', age: 20 }
];
var html = T.compile($('#t_tmp').html(), 't_tmp')(data);
使い方も簡単です.