在Handlebars JS中,是否有一种方法可以将逻辑运算符合并到标准的handlebars.js条件运算符中?就像这样:
{{#if section1 || section2}}
.. content
{{/if}}
我知道我可以编写自己的帮助程序,但首先我想确保我没有重复造轮子。
在Handlebars JS中,是否有一种方法可以将逻辑运算符合并到标准的handlebars.js条件运算符中?就像这样:
{{#if section1 || section2}}
.. content
{{/if}}
我知道我可以编写自己的帮助程序,但首先我想确保我没有重复造轮子。
通过“欺骗”块助手是可能的。这可能违背了开发Handlebars的人的意识形态。
Handlebars.registerHelper('ifCond', function(v1, v2, options) {
if(v1 === v2) {
return options.fn(this);
}
return options.inverse(this);
});
你可以在模板中像这样调用helper。{{#ifCond v1 v2}}
{{v1}} is equal to {{v2}}
{{else}}
{{v1}} is not equal to {{v2}}
{{/ifCond}}
registerBoundHelper
无法处理Handlebars语法。解决方法是创建一个自定义视图:https://dev59.com/-nXYa4cB1Zd3GeqP3TGm - Warren Seine将解决方案进一步完善,增加了比较操作符。
Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {
switch (operator) {
case '==':
return (v1 == v2) ? options.fn(this) : options.inverse(this);
case '===':
return (v1 === v2) ? options.fn(this) : options.inverse(this);
case '!=':
return (v1 != v2) ? options.fn(this) : options.inverse(this);
case '!==':
return (v1 !== v2) ? options.fn(this) : options.inverse(this);
case '<':
return (v1 < v2) ? options.fn(this) : options.inverse(this);
case '<=':
return (v1 <= v2) ? options.fn(this) : options.inverse(this);
case '>':
return (v1 > v2) ? options.fn(this) : options.inverse(this);
case '>=':
return (v1 >= v2) ? options.fn(this) : options.inverse(this);
case '&&':
return (v1 && v2) ? options.fn(this) : options.inverse(this);
case '||':
return (v1 || v2) ? options.fn(this) : options.inverse(this);
default:
return options.inverse(this);
}
});
像这样在模板中使用它:
{{#ifCond var1 '==' var2}}
CoffeeScript 版本
Handlebars.registerHelper 'ifCond', (v1, operator, v2, options) ->
switch operator
when '==', '===', 'is'
return if v1 is v2 then options.fn this else options.inverse this
when '!=', '!=='
return if v1 != v2 then options.fn this else options.inverse this
when '<'
return if v1 < v2 then options.fn this else options.inverse this
when '<='
return if v1 <= v2 then options.fn this else options.inverse this
when '>'
return if v1 > v2 then options.fn this else options.inverse this
when '>='
return if v1 >= v2 then options.fn this else options.inverse this
when '&&', 'and'
return if v1 and v2 then options.fn this else options.inverse this
when '||', 'or'
return if v1 or v2 then options.fn this else options.inverse this
else
return options.inverse this
'||'
和 '&&'
。我添加了这些情况,它们非常有用。 - Jasonv1 = Ember.Handlebars.get(this, v1, options)
v2 = Ember.Handlebars.get(this, v2, options)
- ZX12RHandlebars支持嵌套操作,如果我们按照不同的逻辑编写代码,则提供了很大的灵活性(和更清晰的代码)。
{{#if (or section1 section2)}}
.. content
{{/if}}
实际上,我们可以添加各种各样的逻辑:
{{#if (or
(eq section1 "foo")
(ne section2 "bar"))}}
.. content
{{/if}}
只需注册这些帮助程序:
Handlebars.registerHelper({
eq: (v1, v2) => v1 === v2,
ne: (v1, v2) => v1 !== v2,
lt: (v1, v2) => v1 < v2,
gt: (v1, v2) => v1 > v2,
lte: (v1, v2) => v1 <= v2,
gte: (v1, v2) => v1 >= v2,
and() {
return Array.prototype.every.call(arguments, Boolean);
},
or() {
return Array.prototype.slice.call(arguments, 0, -1).some(Boolean);
}
});
and
和 or
助手仅适用于2个参数,这不是您想要的。我修改了 and
和 or
工具来支持超过两个参数。使用这个一行代码作为 and
: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);
并且使用这个一行代码作为 or
: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);
。 - Luketn: function(v1, v2, v3) { return v1 ? v2 : v3; }
。用法:{{#if (tn someCondition valueIfTrue valueIfFalse)}}
。 - kevlened如果你喜欢冒险,那么这篇文章就是为你准备的。
要点: https://gist.github.com/akhoury/9118682 演示: 下面的代码片段
{{#xif EXPRESSION}} {{else}} {{/xif}}
encodeURIComponent(property)
template( {name: 'Sam', age: '20' } )
, 注意 age
是一个 string
,这样我就可以在本文后面演示 parseInt()
<p>
{{#xif " name == 'Sam' && age === '12' " }}
BOOM
{{else}}
BAMM
{{/xif}}
</p>
<p>
BOOM
</p>
Handlebars.registerHelper("xif", function (expression, options) {
return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
});
{{x EXPRESSION}}
parseInt(property)
template({name:'Sam',age:'20'})
,age
是一个string
,只是为演示目的,它可以是任何内容..<p>Url: {{x "'hi' + name + ', ' + window.location.href + ' <---- this is your href,' + ' your Age is:' + parseInt(this.age, 10)"}}</p>
<p>Url: hi Sam, http://example.com <---- this is your href, your Age is: 20</p>
这看起来有点长,因为我为了清晰起见扩展了语法并对几乎每一行进行了注释。
Handlebars.registerHelper("x", function(expression, options) {
var result;
// you can change the context, or merge it with options.data, options.hash
var context = this;
// yup, i use 'with' here to expose the context's properties as block variables
// you don't need to do {{x 'this.age + 2'}}
// but you can also do {{x 'age + 2'}}
// HOWEVER including an UNINITIALIZED var in a expression will return undefined as the result.
with(context) {
result = (function() {
try {
return eval(expression);
} catch (e) {
console.warn('•Expression: {{x \'' + expression + '\'}}\n•JS-Error: ', e, '\n•Context: ', context);
}
}).call(context); // to make eval's lexical this=context
}
return result;
});
Handlebars.registerHelper("xif", function(expression, options) {
return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
});
var data = [{
firstName: 'Joan',
age: '21',
email: 'joan@aaa.bbb'
}, {
firstName: 'Sam',
age: '18',
email: 'sam@aaa.bbb'
}, {
firstName: 'Perter',
lastName: 'Smith',
age: '25',
email: 'joseph@aaa.bbb'
}];
var source = $("#template").html();
var template = Handlebars.compile(source);
$("#main").html(template(data));
h1 {
font-size: large;
}
.content {
padding: 10px;
}
.person {
padding: 5px;
margin: 5px;
border: 1px solid grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0/handlebars.min.js"></script>
<script id="template" type="text/x-handlebars-template"></script>
<div id="main"></div>
如果您想要访问上层作用域,这个稍微有些不同,表达式是所有参数的连接,用法:说上下文数据看起来像这样:
// data
{name: 'Sam', age: '20', address: { city: 'yomomaz' } }
// in template
// notice how the expression wrap all the string with quotes, and even the variables
// as they will become strings by the time they hit the helper
// play with it, you will immediately see the errored expressions and figure it out
{{#with address}}
{{z '"hi " + "' ../this.name '" + " you live with " + "' city '"' }}
{{/with}}
Handlebars.registerHelper("z", function () {
var options = arguments[arguments.length - 1]
delete arguments[arguments.length - 1];
return Handlebars.helpers["x"].apply(this, [Array.prototype.slice.call(arguments, 0).join(''), options]);
});
Handlebars.registerHelper("zif", function () {
var options = arguments[arguments.length - 1]
delete arguments[arguments.length - 1];
return Handlebars.helpers["x"].apply(this, [Array.prototype.slice.call(arguments, 0).join(''), options]) ? options.fn(this) : options.inverse(this);
});
{{#each}} ... {{xif ' ../name === this.name' }} {{/each}}
... 但我仍在调查中。 - bentael{{z ...}}
帮助程序。 - bentaeleval(expression);
替换为 eval('(function(){try{return ' + expression + ';}catch(e){}})();');
- 我知道这看起来很丑陋,但我无法想到更安全的方法 - 请注意,这个执行速度不是很快,所以在大量迭代中不要使用。 - bentael{{#if cond1}}
{{#if con2}}
<div> and condition completed</div>
{{/if}}
{{else}}
<div> both conditions weren't true</div>
{{/if}}
编辑:相反,你可以通过以下方法执行或操作:
{{#if cond1}}
<div> or condition completed</div>
{{else}}
{{#if cond2}}
<div> or condition completed</div>
{{else}}
<div> neither of the conditions were true</div>
{{/if}}
{{/if}}
编辑/备注:从handlebars的官网handlebarsjs.com获取,以下是假值:
您可以使用if帮助器有条件地呈现一个块。如果其参数返回false、undefined、null、""或[](一个“falsy”值),那么任何'cond'(如cond1或cond2)都不会被视为真。
这里所有回答的问题是它们不能与绑定属性一起使用,即当涉及的属性更改时,if条件不会重新评估。这是一个稍微高级一点的帮助程序版本,支持绑定。它使用Ember源代码中的 bind 函数,该函数也用于实现正常的Ember #if
助手。
这个版本仅限于左侧的单个绑定属性与右侧的常量进行比较,我认为它对于大多数实际目的来说已经足够好了。如果您需要比简单比较更高级的东西,那么也许最好开始声明一些计算属性并使用普通的#if
助手。
Ember.Handlebars.registerHelper('ifeq', function(a, b, options) {
return Ember.Handlebars.bind.call(options.contexts[0], a, options, true, function(result) {
return result === b;
});
});
你可以像这样使用它:
{{#ifeq obj.some.property "something"}}
They are equal!
{{/ifeq}}
如果您想检查多个条件,这里有一个解决方案:
/* Handler to check multiple conditions
*/
Handlebars.registerHelper('checkIf', function (v1,o1,v2,mainOperator,v3,o2,v4,options) {
var operators = {
'==': function(a, b){ return a==b},
'===': function(a, b){ return a===b},
'!=': function(a, b){ return a!=b},
'!==': function(a, b){ return a!==b},
'<': function(a, b){ return a<b},
'<=': function(a, b){ return a<=b},
'>': function(a, b){ return a>b},
'>=': function(a, b){ return a>=b},
'&&': function(a, b){ return a&&b},
'||': function(a, b){ return a||b},
}
var a1 = operators[o1](v1,v2);
var a2 = operators[o2](v3,v4);
var isTrue = operators[mainOperator](a1, a2);
return isTrue ? options.fn(this) : options.inverse(this);
});
使用方法:
/* if(list.length>0 && public){}*/
{{#checkIf list.length '>' 0 '&&' public '==' true}} <p>condition satisfied</p>{{/checkIf}}
基本上适用于任何二元运算符的改进解决方案(至少适用于数字,字符串在使用eval时不太有效,注意如果使用非定义运算符与用户输入一起可能会发生脚本注入):
Handlebars.registerHelper("ifCond",function(v1,operator,v2,options) {
switch (operator)
{
case "==":
return (v1==v2)?options.fn(this):options.inverse(this);
case "!=":
return (v1!=v2)?options.fn(this):options.inverse(this);
case "===":
return (v1===v2)?options.fn(this):options.inverse(this);
case "!==":
return (v1!==v2)?options.fn(this):options.inverse(this);
case "&&":
return (v1&&v2)?options.fn(this):options.inverse(this);
case "||":
return (v1||v2)?options.fn(this):options.inverse(this);
case "<":
return (v1<v2)?options.fn(this):options.inverse(this);
case "<=":
return (v1<=v2)?options.fn(this):options.inverse(this);
case ">":
return (v1>v2)?options.fn(this):options.inverse(this);
case ">=":
return (v1>=v2)?options.fn(this):options.inverse(this);
default:
return eval(""+v1+operator+v2)?options.fn(this):options.inverse(this);
}
});
这是我使用的块助手链接:比较块助手。它支持所有标准运算符,并允许您编写如下所示的代码。它真的非常方便。
{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}
又一个有问题的三元助手的解决方案:
'?:' ( condition, first, second ) {
return condition ? first : second;
}
<span>{{?: fooExists 'found it' 'nope, sorry'}}</span>
或者一个简单的合并辅助函数:
'??' ( first, second ) {
return first ? first : second;
}
<span>{{?? foo bar}}</span>
由于这些字符在handlebars标记中没有特殊的含义,因此您可以自由地将它们用于辅助程序名称。