10

我正在尝试使用 Mustache.js 构建一个 html 树,但它无法抛出“超出最大调用堆栈大小”,可能是因为无限递归。

怎么了?

var Mustache = require('mustache');

var root = {
    title: 'Gar1',
    children: [{title: 'gar2'}, {title: 'gar3', children: [{title: 'gar4'}]}]
};

var panelTemplate = '{{title}}<ul>{{#children}}<li>{{>panel}}</li>{{/children}}</ul>';

var partials = {panel: panelTemplate};
var output = Mustache.render(panelTemplate, root, partials);


console.log(output);
4

2 回答 2

18

The problem is inherent to the implementation in Mustache.js (disclaimer: not sure if the problem is in the spec itself) as the algorithm looks for a property on its parent when it can't find it on the current context.

To explain it briefly: code runs on your template, outputs Gar1<ul> and finds a {{#children}} tag. Since your context has a children tag it outputs the <li> and invokes the partial which will now run on the inner context {title: 'gar2'}. When Mustache reaches your {{#children}} tag again, it now finds out that the current context has no children property, thus it goes one level up where it actually finds your children property and starts recursing (is this a real word?) again on itself like mad.

Two possible solutions:

1 - modify your data so that all entries have a children property, and when a node should have no children set it to false or null (not an empty array) like this:

var root = {
    title: 'Gar1',
    children: [{title: 'gar2', children: false}, {title: 'gar3', children: [{title: 'gar4', children: false}]}]
};

2 - use Handlebars instead of Mustache, and wrap the <ul> in an {{#if children}} tag.

Hope this helps, I know the answer is a bit late since this has been asked.

于 2012-11-27T20:46:57.943 回答
5

这是一个需要递归的对象。

目的

var obj = [
    {
        obj: true,
        key: 'a',
        value: [
            {
                obj: false,
                key: 'a',
                value: 1
            },
            {
                obj: false,
                key: 'b',
                value: 2
            },
            {
                obj: true,
                key: 'c',
                value: [
                    {
                        obj: false,
                        key: 'a',
                        value: 3
                    }
                ]
            }
        ]
    },
    {
        obj: false,
        key: 'b',
        value: 4
    }
];

模板(recursion.html)。

<!-- root -->
<ul>
    {{#value}}
    <li>
        <!-- object -->
        {{#obj}}
        <span><b>{{key}}</b></span>
        {{>object}}
        {{/obj}}
        <!-- value -->
        {{^obj}}
        <span><b>{{key}}</b> <span>{{value}}</span></span>
        {{/obj}}
    </li>
    {{/value}}
</ul>

您传入的第一个对象是根,它key不仅有一个value. 如果value有一个属性obj设置,true那么它是一个对象,打印出它的键并再次递归调用模板以获得它的值。如果不是对象,则不需要递归,只需打印出来。

渲染客户端。

// html is recursion.html contents
var template = Hogan.compile(html),
    content = template.render({value: obj}, {object: html});
// show the rendered template
$('body').empty().append(content);

使用 Express.js 渲染服务器端

res.render('recursion', {
    value: obj,
    partials: {
        object: 'recursion'
    }
});

这个例子的输出

http://jsfiddle.net/simo/GYjMY/

顺便说一句,我正在使用 Hogan.js 来呈现模板。我不知道 Mustache.js 渲染是否支持递归。

于 2013-02-19T20:09:32.437 回答