一个简单的 JavaScript 的模板引擎

比较简单,直接贴代码吧:

(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];\n',
                        'var $data = this || { };\n',
                        'var $escapeHTML = $T.escapeHTML;\n',
                        'var $htmlArr = [];\n',
                        'var $write = function() { Array.prototype.push.apply($htmlArr, arguments); };\n'];

                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(/\n/g, '\\n');
                return '$write("' + code + '");\n';
            }

            function logic(code) {
                code = code.replace(/^\s+/g, '');
                if (code.indexOf('==') === 0) {
                    return '$write(' + code.substring(2) + ');\n';
                } else if (code.indexOf('=') === 0) {
                    return '$write($escapeHTML(' + code.substring(1) + '));\n';
                } else {
                    return code + '\n';
                }
            }
        },
        _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);

 用法也比较简单。

posted on 2014-08-22 21:59  醉仙灵芙  阅读(266)  评论(1编辑  收藏  举报