mustache-0.1源码注解

最近在mustache源码,先看的0.1版本。
cdn上的源码: https://cdn.bootcdn.net/ajax/libs/mustache.js/0.1/mustache.js
下面是我去掉部分无用字段后的注释,不过里面render_partial函数参数eval之后是对象的形式,没搞懂(-.-)。有知道的大神还望指导一下;

/*
  Shamless port of http://github.com/defunkt/mustache
    by Jan Lehnardt 
  Thanks @defunkt for the awesome code
  TBD: MIT, see LICENSE
  
  ChangeLog:
   - 04.10.2009: Ininitial port at http://devhouseberlin.de/
*/
var Mustache = {
    name: "mustache.js",
    version: "0.1",

    context: {}, // 处理的数据
    // 其实就是render函数,,中间传递而已
    to_html: function (template, view) {
        return this.render(template, view);
    },
    render: function (template, view) {
        // 没有双大阔号 就不用模板直接返回
        if (template.indexOf("{{") == -1) {
            return template;
        }
        // 把数据 合并,下面可能或获取第二个模板,第二个模板也有数据,数据需要合并
        this.context = context = this.merge((this.context || {}), view);
        // 递归 处理循环 渲染  (可以先看简单渲染,之后再来看 #循环的渲染)
        var html = this.render_section(template);
        //  递归可能把事情搞砸了
        this.context = context;
        // 简单的渲染
        return this.render_tags(html);
    },
    render_partial: function (name) {
        // 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
        var evil_name = eval(name)
        switch (typeof evil_name) {
            case "string":
                // 如果是字符串 那window下的这个evil_name 作为模板,再次渲染
                return this.to_html(evil_name, "");
            case "object":
                // 如果是对象,那添加_template 作为模板继续渲染,既然typeof是对象, 那就只能是[] , {}, null; 但是这样不符合变量命名规范,,,不懂。。。。
                var tpl = name + "_template";
                return this.to_html(eval(tpl), evil_name);
            default:
                throw ("Unknown partial type.");
        }
    },
    merge: function (a, b) {
        // 遍历 如果是自身的属性,那添加给a
        for (var name in b) {
            if (b.hasOwnProperty(name)) {
                a[name] = b[name];
            }
        }
        return a;
    },
    render_section: function (template) {
        // 如果没有{{# 说明不是遍历循环直接返回
        if (template.indexOf("{{#") == -1) {
            return template;
        }
        var that = this;
        // {{#        (.+)             }}     \s*           ([\s\S]+)    {{/ \1}}          \s*   }}
        // 开始      匹配循环关键字      结束    可能有空格       全匹配       以\开始的匹配关键字  空格
        return template.replace(/\{\{\#(.+)\}\}\s*([\s\S]+)\{\{\/\1\}\}\s*/mg,
            // name  循环关键字   content  全匹配的内容
            function (match, name, content) {
                var value = that.find(name);
                // 如果数据中 查找到数据是 数组
                if (that.is_array(value)) {
                    // 遍历数组  数组每一项都渲染,以全匹配 为模板,,数组每一项为数据,  调研render函数。最后join合并
                    // 比如  value = [{age:'100', name:'child1'},{'age':'200', name:"child2"}]
                    // content = 姓名:{{name}}年龄:{{age}}
                    // that.render(content, value) 会得到 姓名:child1年龄:100  姓名:child2年龄:200
                    return value.map(function (row) {
                        return that.render(content, row);
                    }).join('');
                //  // 如果数据中 查找到数据是 不是数组 但是存在   再调用render函数渲染  ,content 为模板
                } else if (value) {
                    return that.render(content);
                } else {
                    // 没有 直接返回空字符串
                    return "";
                }
            }
        );
    },
    // 判断是数组
    is_array: function (a) {
        return (a &&
            typeof a === 'object' &&
            a.constructor === Array);
    },
    // 简单渲染
    render_tags: function (template) {

        var that = this;
        // {{  (! | < | {)?  ([^ / #]+?)     \1 ?}}+
        //     !或< 或 {      非/#的数据     !或< 或 {     
        return template.replace(/\{\{(!|<|\{)?([^\/#]+?)\1?\}\}+/mg,
            // match 匹配正则  operator 第一个括号匹配项  name第二个括号匹配项
            function (match, operator, name) {
                switch (operator) {
                    case "!": // ignore comments 注释
                        return match;
                    case "<": // render partial 渲染部分
                        return that.render_partial(name);
                    case '{': // the triple mustache is unescaped  // {{{ 三个大括号是不会转义的
                        return that.find(name);
                    default: // escape the value  会转义
                        return that.escape(that.find(name));
                }
            }, this);
    },
    // 转义 以防有脚本
    escape: function (s) {
        return s.toString().replace(/[&"<>\\]/g, function (s) {
            switch (s) {
                case "&":
                    return "&";
                case "\\":
                    return "\\\\";;
                case '"':
                    return '\"';;
                case "<":
                    return "<";
                case ">":
                    return ">";
                default:
                    return s;
            }
        });
    },
    // 找到数据中 对应的值,如果是函数执行,不存在报错,否则返回
    find: function (name) {
        name = this.trim(name);
        
        var context = this.context;
        if (typeof context[name] === "function") {
            return context[name].apply(context);
        }
        if (context[name] !== undefined) {
            return context[name];
        }
        throw ("Can't find " + name + " in " + context);
    },
    // 去掉空格
    trim: function (s) {
        return s.replace(/^\s*|\s*$/g, '');
    },
};

html



  
    
    
    
    Document
  
  
    

控制台打印结果

str

child2

200

{{!我是注释}}

abc&<

666

abc&<


姓名:child1年龄:100
姓名:child2年龄:200

你可能感兴趣的:(mustache-0.1源码注解)