Javascript 动态计算把手模板的值?

Javascript 动态计算把手模板的值?,javascript,handlebars.js,Javascript,Handlebars.js,有没有一种方法可以在需要时为把手提供一个计算值的函数,而不是在上下文中预先提供所有值 例如,假设我想用示例数据填写任何模板: var exampleFunction = function (varName) { return "Example " + varName; }; 如果我提前知道Handlebar模板需要什么变量,我可以使用这个函数来组装上下文。然而,我真正想做的是: var template = Handlebars.compile(templateString); var

有没有一种方法可以在需要时为把手提供一个计算值的函数,而不是在上下文中预先提供所有值

例如,假设我想用示例数据填写任何模板:

var exampleFunction = function (varName) {
    return "Example " + varName;
};
如果我提前知道Handlebar模板需要什么变量,我可以使用这个函数来组装上下文。然而,我真正想做的是:

var template = Handlebars.compile(templateString);
var html = template.fillFromFunction(exampleFunction);
这可能吗?如果没有,那么还有其他模板引擎支持它吗


附加问题:是否可以使其异步,例如:

var template = Handlebars.compile('{{foo.bar}}');
var dataFunction = function (path, callback) {
    setTimeout(function () {
        callback("Async " + path);
    }, 100);
};
简短版本: 这是一个黑客,但我有一个解决办法

var oldNameLookup = handlebars.JavaScriptCompiler.prototype.nameLookup;
handlebars.JavaScriptCompiler.prototype.nameLookup = function (parent, name) {
    return '(typeof ' + parent + ' === "function" ? '
        + parent + '(' + JSON.stringify(name) + ') : '
        + oldNameLookup(parent, name) + ')';
}
用法:

var template = handlebars.compile('{{foo}} {{bar}}');
var dataFunction = function (key) {
    return 'data:' + key;
};
console.log(template(dataFunction));
// Outputs: "data:foo data:bar"
var template = handlebars.compile('{{foo}} {{foo.bar}}');
var dataFunction = transformFunc(function (path) {
    // path is a JSON Pointer path
    return "data:" + path;
});
console.log(template(dataFunction));
// Outputs: "data:/foo data:/foo/bar"
子属性: 要启用子属性(例如,
“{{foo.bar}}”
),我们需要一个包装器方法:

function transformFunc(dataFunction) {
    return function (key) {
        if (typeof key !== 'string') {
            return dataFunction('');
        }
        var pointerKey = '/' + key.replace(/~/g, '~0').replace(/\//g, '~1');
        return transformFunc(function (path) {
            return dataFunction(pointerKey + path);
        });
    };
}
用法:

var template = handlebars.compile('{{foo}} {{bar}}');
var dataFunction = function (key) {
    return 'data:' + key;
};
console.log(template(dataFunction));
// Outputs: "data:foo data:bar"
var template = handlebars.compile('{{foo}} {{foo.bar}}');
var dataFunction = transformFunc(function (path) {
    // path is a JSON Pointer path
    return "data:" + path;
});
console.log(template(dataFunction));
// Outputs: "data:/foo data:/foo/bar"
如果需要,我想可以修改
.compile()
.precompile()
,以便在模板化时将
transformFunc()
应用于任何传入函数

说明: 黑客包括改变车把的代码生成,但这意味着这是一种OK。我试图找到一种方法来创建子类,但看不到如何获取或使用它

短版本:覆盖。 此方法通常生成JavaScript代码,如
depth0.foo
(depth1&&depth1.bar)
。我们正在对其进行扩展,以便生成的代码首先检查
父项
,查看它是否是函数

如果它是一个函数,那么它将以属性名作为参数调用该函数。否则,它将返回与前面相同的值。例如,它将生成如下内容:

(typeof depth0 === "function" ? depth0("foo") : (depth0 && depth0.foo))
对于简单变量(例如just
“{{foo}}”
),您现在可以只提供一个函数,并使用变量名调用它

启用子属性 然而,对于嵌套属性(即,
“{{foo.bar.baz}}”
),我们实际上需要我们的函数返回另一个函数,该函数可以返回适当的数据,也可以使用另一个属性名调用,具体取决于需要什么

因此:如果我们的转换函数没有给定字符串,那么就假定我们在端点(我们想要的是实际数据,而不是子属性),所以我们只调用它


如果我们的转换函数被赋予一个字符串,那么它被假定为一个键,因此另一个(转换的)函数是return,它调用data函数,并适当地在参数前面加上前缀。

我没有额外的分数,因为这不是异步的。我想我会活下去的。