【问题标题】:Recursion with doT.js使用 doT.js 进行递归
【发布时间】:2012-12-30 18:57:09
【问题描述】:

假设我有这样的数据结构:

{ list: [ {
         name: "1",
         children: [{
               name: "1.1",
               children: []
            },
            {
               name: "1.2",
               children: [{
                     name: "1.2.1",
                     children: []
                  }
               ]
            }
         ]
      },
      {
         name: "2",
         children: [{
               name: "2.1",
               children: [{
                     name: "2.1.1",
                     children: []
                  },           
                  {
                     name: "2.1.2",
                     children: []
                  },               
                  {
                     name: "2.1.3",
                     children: []
                  }
               ]
            },
            {
               name:  "2.2",
               children: []
            },
            {
               name: "2.3",
               children: []
            }
         ]
      },
      {
         name: "3",
         children: [{
               name: "3.1",
               children: []
            }
         ]
      }
   ]
}

我将如何使用 doT.js 创建一个模板,该模板将递归地遍历对象并构建嵌套列表?

使用递归函数直接在 JS 中构建 html 字符串非常简单:(http://jsfiddle.net/fergal_doyle/WN8hZ/5/)

var html = "";
function buildList(a){

    if (a.length == 0){return};

    html += "<ul>";
    for (var i = 0; i < a.length; i++)
    {
        html += "<li>" + a[i].name;
        buildList(a[i].children);
        html += "</li>";
    }
    html += "</ul>";            
}
buildList(data.list);

$("#out").html(html);


但是有了 doT.js,这就是我所拥有的,然后我就难住了! (http://jsfiddle.net/fergal_doyle/BTZpu/4/)

编辑: 我可以通过混合一些带有评估的 JS 来做到这一点 (http://jsfiddle.net/fergal_doyle/he8AN/)

{{ function buildList(a) { }}

    {{?a.length}}
    <ul>
        {{~a :v}}
        <li>
            {{=v.name}}
            {{ buildList(v.children); }}
        </li>
        {{~}}
    </ul>
    {{?}}

{{ } }}

{{ buildList( it.list ); }}

我试图使用部分来实现它。定义一个 ul sn-p 然后让该 sn-p 调用自己作为参数传入一个数组,但我得到一个“递归过多”错误。如果有任何方法可以使下面的工作,它比我认为的上面要整洁得多。 (http://jsfiddle.net/fergal_doyle/qazGe/4/)

{{##def.ul:a:
    <ul>
    {{~a :value}}
        <li>{{=value.name}}{{#def.ul:value.children}}</li>
    {{~}}
    </ul>
#}}

{{#def.ul:it.list}}

【问题讨论】:

    标签: javascript templates dot.js


    【解决方案1】:

    问题在于编译时。 doT.js 似乎没有处理部分递归。您的递归代码{{#def.ul:value.children}} 使 doT.js 库无限地解析/替换它为您的函数的内容。解决此问题的一种方法是使用 arguments.callee 在您的部分中引用您的部分。这是你的FIDDLE 的一个分支

    {{##def.ul:a:
      <ul>
      {{~a :value}}
        <li>{{=value.name}}{{=arguments.callee(value.children)}}</li>
      {{~}}
      </ul>
    #}}
    
    {{#def.ul:it}}
    

    库的作者可以通过以下方式在他们的库中实现相同的想法(未经测试):

    function resolveDefs(c, block, def) {
        return ((typeof block === 'string') ? block : block.toString())
        .replace(c.define || skip, function(m, code, assign, value) {
            if (code.indexOf('def.') === 0) {
                code = code.substring(4);
            }
            if (!(code in def)) {
    
                // HANDLE RECURSION START
                value = value.replace(c.use || skip, function(m, recursiveCode) {
                    if (c.useParams) return recursiveCode.replace(c.useParams, function(m, s, d, param) {
                        if(d == code) {
                            var ret = s + "{{=arguments.callee(";
                            if(param)
                                ret += param;
                            return ret + ")}}";
                        }
                    });
    
                })
                // HANDLE RECURSION END
    
                if (assign === ':') {
    ...
    

    【讨论】:

      猜你喜欢
      • 2011-06-04
      • 2018-11-02
      • 2015-02-02
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多