vapour's blog

10Aug/110

轻量级模板系统

开发问卷系统时,开发了一个简单的模板管理功能。实现了简单的变量替换、循环、自定义函数、并提供了循环变量tmCount(从0开始)和tmNumber(从1开始)。不多说,先上代码:

var templateManager = (function () {
    var templates = {},
        tmp,
        supplant = {
            init: function (str, params) {
                var value, prop, tmp, len;
                for (prop in params) {
                    if (params.hasOwnProperty(prop)) {
                        value = params[prop];
                        switch (Object.prototype.toString.call(value)) {
                            case '[object Number]':
                            case '[object String]':
                                tmp = {};
                                tmp[prop] = value;
                                str = supplant.replaceString(str, tmp);
                                break;
                            case '[object Function]':
                                str = supplant.replaceFunc(str, prop, value, params);
                                break;
                            case '[object Array]':
                                str = supplant.replaceArray(str, prop, value);
                                break;
                            default:
                                break;
                        }
                    }
                }
                return str;
            },
            replaceString: function (str, params) {
                var prop;
                for (prop in params) {
                    if (params.hasOwnProperty(prop)) {
                        str = str.split('{' + prop + '}').join(params[prop]);
                    }
                }
                return str;
            },
            replaceFunc: function (str, prop, func, item) {
                return str.split('{' + prop + '}').join(func(item));
            },
            replaceArray: function (str, prop, data) {
                var i = 0,
                    left,
                    middle,
                    right,
                    s = '{#' + prop + '}',
                    e = '{/' + prop + '}',
                    len = data.length,
                    start = 0,
                    end = 0;
                    
                start = str.indexOf(s);
                end = str.indexOf(e, start);
                left = str.slice(0, start);
                middle = str.slice(start + s.length, end);
                right = str.slice(end + e.length);
                if (len > 0 && start > -1) {
                    for (; i < len; ++i) {
                        data[i].tmCount = i;
                        data[i].tmNumber = i + 1;
                        if (data[i].content !== null) { //如果content属性不等于null
                            left += supplant.init(middle, data[i]);
                        } else {
                            left += data[i].replace;
                        }
                    }
                    str = left + right;
                    
                    if (str.indexOf(s) > -1) {//如果包括多个循环
                        str = supplant.replaceArray(str, prop, data);
                    }
                }
                
                if (len == 0 && start > -1) {
                    str = left + right;
                }
                
                return str;
            }
        };
    
    return {
        render: function (name, params) {
            if (typeof templates[name] !== 'string') {
                throw 'Template ' + name + ' not found!';
            }
            tmp = name;
            return supplant.init(templates[name], params);
        },
        defineTemplate: function (name, template) {
            if (typeof template == 'string') {
                templates[name] = template;
            } else { //数组
                templates[name] = template.join('');
            }
        }
    };
})();

上面代码中定义一个templateManager对象用来管理模板,提供了两个接口:

  1. defineTemplate 用来定义模板
  2. render 用来渲染模板

内部私有的supplant对象实现模板引擎,提供了替换变量、替换循环、替换函数的功能。

文档和示例:

//替换变量
templateManager.defineTemplate('profile', '姓名:{name},blog:{blog}');
templateManager.render('profile', {name: 'vapour', blog: 'http://dovapour.info/'});
//结果 姓名:vapour,blog:http://dovapour.info/

//实现循环
templateManager.defineTemplate('website', [
    '<ul>',
        '{#webs}<li><a href="{url}">{name}<_buff_29_buff_li>{/webs}',
    '<ul>'
]);
templateManager.render('website', {
    webs: [{
        name: '百度',
        url: 'http://www.baidu.com/',
        getLen: function (item) {
            return item.url.length;
        }
    }, {
        name: '淘宝',
        url: 'http://www.taobao.com/',
        getLen: function (item) {
            return item.url.length;
        }
    }, {
        name: '腾讯',
        url: 'http://www.qq.com/',
        getLen: function (item) {
            return item.url.length;
        }
    }, {
        name: '网易',
        url: 'http://163.com/',
        getLen: function (item) {
            return item.url.length;
        }
    }, {
        name: '新浪',
        url: 'http://www.sina.com/',
        getLen: function (item) {
            return item.url.length;
        }
    }]
});
/*
<ul>
    <li><a href="http://www.baidu.com/">百度</a>,url长度21</li>
    <li><a href="http://www.taobao.com/">淘宝</a>,url长度22</li>
    <li><a href="http://www.qq.com/">腾讯</a>,url长度18</li>
    <li><a href="http://163.com/">网易</a>,url长度15</li>
    <li><a href="http://www.sina.com/">新浪</a>,url长度20</li>
<ul>
*/

Tagged as: No Comments