有没有办法为Handlebars提供一个在需要时计算值的函数,而不是在上下文中预先提供所有值?
例如,假设我想用示例数据填写任何模板:
var exampleFunction = function (varName) {
return "Example " + varName;
};
如果我提前知道Handlebars模板需要哪些变量,我可以使用此函数来组合上下文。但是,我真正想做的是:
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);
};
答案 0 :(得分:0)
这是一个黑客,但我有一个解决方法。
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"
要启用子属性(例如"{{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}} {{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()
应用于任何传入函数。
黑客攻击包括改变Handlebars的代码生成,但是这个code comment意味着这没有问题。我试图找到一种子类的方法,但看不到如何让this或this使用它。
nameLookup()
method。此方法通常会生成JavaScript代码,例如depth0.foo
或(depth1 && depth1.bar)
。我们正在扩展它,以便生成的代码首先检查parent
以查看它是否是一个函数。
如果它是一个函数,则它以属性名称作为参数调用该函数。否则,它返回与先前相同的值。例如,它将生成如下内容:
(typeof depth0 === "function" ? depth0("foo") : (depth0 && depth0.foo))
对于简单变量(例如,仅"{{foo}}"
),您现在可以只提供一个函数,并使用变量名调用它。
但是,对于嵌套属性(即"{{foo.bar.baz}}"
),我们实际上需要我们的函数来返回另一个函数,该函数可以返回适当的数据,也可以使用另一个属性名称调用,具体取决于需要的。
所以:如果我们的转换函数没有给出一个字符串,那么假设我们处于终点(我们想要实际的数据,而不是子属性),所以我们只需要调用。
如果我们的转换函数被赋予一个字符串,那么它被假定为一个键,所以另一个(转换的)函数是返回,它返回数据函数,为参数添加适当的前缀。