簡単なJavaScriptのテンプレートエンジン

5693 ワード

比較的簡単です.直接コードを貼りましょう.
(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);

 使い方も簡単です.