Javascript handlebar.js{{{if}}条件中的逻辑运算符

Javascript handlebar.js{{{if}}条件中的逻辑运算符,javascript,handlebars.js,Javascript,Handlebars.js,Handlebar JS中是否有方法将逻辑运算符合并到标准handlebar.JS条件运算符中?大概是这样的: {{#if section1 || section2}} .. content {{/if}} {{#ifCond var1 '==' var2}} Handlebars.registerHelper( "compare", function( v1, op, v2, options ) { var c = { "eq": function( v1, v2 ) {

Handlebar JS中是否有方法将逻辑运算符合并到标准handlebar.JS条件运算符中?大概是这样的:

{{#if section1 || section2}}
.. content
{{/if}}
{{#ifCond var1 '==' var2}}
Handlebars.registerHelper( "compare", function( v1, op, v2, options ) {

  var c = {
    "eq": function( v1, v2 ) {
      return v1 == v2;
    },
    "neq": function( v1, v2 ) {
      return v1 != v2;
    },
    ...
  }

  if( Object.prototype.hasOwnProperty.call( c, op ) ) {
    return c[ op ].call( this, v1, v2 ) ? options.fn( this ) : options.inverse( this );
  }
  return options.inverse( this );
} );
{{#ifeq obj.some.property "something"}}
  They are equal!
{{/ifeq}}
// used as sub-expression
{{#each item in model}}
  {{#if (js-x "this.section1 || this.section2" item)}}
  {{/if}}
{{/each}}

// used normally
{{js-x "p0 || p1" model.name model.offer.name}}

我知道我可以编写自己的助手,但首先我要确保我没有重新发明轮子。

这可以通过使用块助手“作弊”实现。这可能违背了开发车把的人的意识形态

Handlebars.registerHelper('ifCond', function(v1, v2, options) {
  if(v1 === v2) {
    return options.fn(this);
  }
  return options.inverse(this);
});
然后可以像这样调用模板中的帮助器

{{#ifCond v1 v2}}
    {{v1}} is equal to {{v2}}
{{else}}
    {{v1}} is not equal to {{v2}}
{{/ifCond}}

将解决方案向前推进一步。这将添加比较运算符

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);
    }
});
咖啡脚本版本

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
handlebar.registerHelper'ifCond',(v1,运算符,v2,选项)->
开关操作员
当“=”、“=”、“是”
如果v1为v2,则返回options.fn此为else options.inverse此为
当“!=”时,“!=”
如果v1!=v2然后是options.fn此为else options.inverse此为
当“=”时
如果v1>=v2,则返回options.fn此为else options.inverse此为
当“&&”、“和”
如果返回v1和v2,则返回options.fn此为else options.inverse此为
当“| |”或“或”
如果返回v1或v2,则返回options.fn此为else options.inverse此为
其他的
返回选项。反转此选项

有一种简单的方法可以做到这一点,而无需编写助手函数。。。它可以完全在模板内完成

{{#if cond1}}   
  {{#if con2}}   
    <div> and condition completed</div>  
  {{/if}}
{{else}}   
  <div> both conditions weren't true</div>  
{{/if}}
{{#if cond1}
{{#if con2}}
和条件已完成
{{/if}
{{else}
这两种情况都不是真的
{{/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}}
{{#if cond1}
或条件已完成
{{else}
{{#如果条件为2}}
或条件已完成
{{else}
这两种情况都不是真的
{{/if}
{{/if}
编辑/注意:来自车把网站:handlebarsjs.com以下是falsy值:

可以使用if辅助对象有条件地渲染块。如果是 参数返回false、undefined、null“”或[](一个“falsy”值), 那么任何“cond”(如cond1或cond2)都不会被计算为true


我发现了一个用CoffeeScript制作的npm软件包,里面有很多非常有用的把手助手。查看以下URL中的文档:

你可以做一个
wgethttp://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgz
下载它们并查看软件包的内容


您将能够执行类似于Jim的回答的
{{{是数字5}}
{{formattate date”%m/%d/%Y}

的操作,但利用一点创造力,我们也可以执行以下操作:

{{#if section1 || section2}}
.. content
{{/if}}
{{#ifCond var1 '==' var2}}
Handlebars.registerHelper( "compare", function( v1, op, v2, options ) {

  var c = {
    "eq": function( v1, v2 ) {
      return v1 == v2;
    },
    "neq": function( v1, v2 ) {
      return v1 != v2;
    },
    ...
  }

  if( Object.prototype.hasOwnProperty.call( c, op ) ) {
    return c[ op ].call( this, v1, v2 ) ? options.fn( this ) : options.inverse( this );
  }
  return options.inverse( this );
} );
{{#ifeq obj.some.property "something"}}
  They are equal!
{{/ifeq}}
// used as sub-expression
{{#each item in model}}
  {{#if (js-x "this.section1 || this.section2" item)}}
  {{/if}}
{{/each}}

// used normally
{{js-x "p0 || p1" model.name model.offer.name}}
然后使用它,我们得到如下结果:

{{#compare numberone "eq" numbretwo}}
  do something
{{else}}
  do something else
{{/compare}}

我建议将对象移出该函数以获得更好的性能,但如果不这样,您可以添加任何您想要的比较函数,包括“and”和“or”。

如果您只想检查是否存在一个或另一个元素,您可以使用此自定义帮助器

Handlebars.registerHelper('if_or', function(elem1, elem2, options) {
  if (Handlebars.Utils.isEmpty(elem1) && Handlebars.Utils.isEmpty(elem2)) {
    return options.inverse(this);
  } else {
    return options.fn(this);
  }
});
像这样

{{#ifCond v1 v2}}
    {{v1}} is equal to {{v2}}
{{else}}
    {{v1}} is not equal to {{v2}}
{{/ifCond}}
{{#if_or elem1 elem2}}
  {{elem1}} or {{elem2}} are present
{{else}}
  not present
{{/if_or}}
如果你还需要有一个“或”来比较 我宁愿添加另一个返回所需结果的属性


模板毕竟应该是无逻辑的

改进的解决方案,基本上适用于任何二进制运算符(至少数字、字符串与eval不兼容,如果使用未定义的运算符和用户输入,请注意可能的脚本注入):

handlebar.registerHelper(“ifCond”,函数(v1,运算符,v2,选项){
开关(操作员)
{
案例“==”:
返回(v1==v2)?options.fn(this):options.inverse(this);
案例“!=”:
返回(v1!=v2)?options.fn(this):options.inverse(this);
案例“=”:
返回(v1==v2)?options.fn(this):options.inverse(this);
案例“!=”:
返回(v1!==v2)?options.fn(this):options.inverse(this);
案例“&&”:
return(v1&&v2)?options.fn(this):options.inverse(this);
格“| |”:
return(v1 | | v2)?options.fn(this):options.inverse(this);
案例“=”:
返回(v1>=v2)?options.fn(this):options.inverse(this);
违约:
返回eval(“+v1+operator+v2)?options.fn(this):options.inverse(this);
}
});

这里有一个指向我使用的块帮助器的链接:。它支持所有标准运算符,并允许您编写如下所示的代码。它真的很方便

{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}

另一种选择是在
#if
中使用函数名。
#if
将检测参数是否为函数,如果为函数,则调用该参数并使用其返回值进行真实性检查。下面的myFunction获取当前上下文作为
this

{{#if myFunction}}
  I'm Happy!
{{/if}}

不幸的是,这些解决方案都不能解决“或”运算符“cond1 | | cond2”的问题

  • 检查第一个值是否为真
  • 使用“^”(或)并检查cond2是否为真

    {{{#如果条件为1}} 做动作 {{^}} {{#如果条件为2}} 做动作 {{/if} {{/if}

  • 它打破了枯燥的规则。那么为什么不使用partial来减少混乱呢

    {{#if cond1}}
        {{> subTemplate}}
    {{^}}
        {{#if cond2}}
            {{> subTemplate}}
        {{/if}}
    {{/if}}
    

    此处发布的所有答案的一个问题是,它们不适用于绑定属性,即当涉及的属性更改时,if条件不会重新计算。下面是支持绑定的帮助器的更高级版本。它使用来自Ember源的函数,该函数还用于实现正常的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;
      });
    });
    
    您可以这样使用它:

    {{#if section1 || section2}}
    .. content
    {{/if}}
    
    {{#ifCond var1 '==' var2}}
    
    Handlebars.registerHelper( "compare", function( v1, op, v2, options ) {
    
      var c = {
        "eq": function( v1, v2 ) {
          return v1 == v2;
        },
        "neq": function( v1, v2 ) {
          return v1 != v2;
        },
        ...
      }
    
      if( Object.prototype.hasOwnProperty.call( c, op ) ) {
        return c[ op ].call( this, v1, v2 ) ? options.fn( this ) : options.inverse( this );
      }
      return options.inverse( this );
    } );
    
    {{#ifeq obj.some.property "something"}}
      They are equal!
    {{/ifeq}}
    
    // used as sub-expression
    {{#each item in model}}
      {{#if (js-x "this.section1 || this.section2" item)}}
      {{/if}}
    {{/each}}
    
    // used normally
    {{js-x "p0 || p1" model.name model.offer.name}}
    

    对于那些在比较对象属性时遇到问题的用户,请在帮助程序中添加此解决方案


    对于那些
    {{#if (if firstCondition firstCondition secondCondition)}}
      (firstCondition || (or) secondCondition) === true
    {{/if}}
    
    {{#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);
        }
    });
    
    {{#if (or section1 section2)}}  
    ...content  
    {{/if}}
    
    {{#if (or (eq section1 "section1") (eq section2 "section2") ) }}  
    ...content  
    {{/if}}
    
    Handlebars.registerHelper("and",function() {
        var args = Array.prototype.slice.call(arguments);
        var options = args[args.length-1];
    
        for(var i=0; i<args.length-1; i++){
            if( !args[i] ){
                return options.inverse(this);
            }
        }
    
        return options.fn(this);
    });
    
    
    Handlebars.registerHelper("or",function() {
        var args = Array.prototype.slice.call(arguments);
        var options = args[args.length-1];
    
        for(var i=0; i<args.length-1; i++){
            if( args[i] ){
                return options.fn(this);
            }
        }
    
        return options.inverse(this);
    }
    
    // Results
    // {{#and foo bar sally bob}} yup {{else}} nope {{/and}} // yup
    // {{#or foo bar "" sally bob}} yup {{else}} nope {{/or}} // yup
    
    // {{#and foo bar "" sally bob}} yup {{else}} nope {{/and}} // nope
    // {{#or "" "" "" "" ""}} yup {{else}} nope {{/or}} // nope
    
    {{#if your_string.match "what_youre_looking_for"}} 
    String found :)
    {{else}}
    No match found :(
    {{/if}}
    
    if(typeof String.includes !== 'function') {
        String.prototype.includes = function(str) {
            if(!(str instanceof RegExp))
                str = new RegExp((str+'').escapeRegExp(),'g');
            return str.test(this);
        }
    }
    
    {{#your_string}}
        {{#if (includes "what_youre_looking_for")}} 
            String found :)
        {{else}}
            No match found :(
        {{/if}}
    {{/your_string}}
    
    {{#if (or(eq firstValue 'String_to_compare_value') (eq secondValue 'String_to_compare_value'))}}business logic goes here{{/if}}
    
    {{#if (and(eq firstValue 'String_to_compare_value') (eq secondValue 'String_to_compare_value'))}}business logic goes here{{/if}}
    
    /* 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}}
    
    Handlebars.registerHelper('and', function () {
        // Get function args and remove last one (function name)
        return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);
    });
    Handlebars.registerHelper('or', function () {
        // Get function args and remove last one (function name)
        return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);
    }); 
    
    {{#if (or (eq questionType 'STARTTIME') (eq questionType 'ENDTIME') (..) ) }}
    
       and: function () {
            return Array.prototype.slice.call(arguments).every(Boolean);
        },
        or: function () {
            return Array.prototype.slice.call(arguments).some(Boolean);
        }
    
    '?:' ( condition, first, second ) {
      return condition ? first : second;
    }
    
    <span>{{?: fooExists 'found it' 'nope, sorry'}}</span>
    
    '??' ( first, second ) {
      return first ? first : second;
    }
    
    <span>{{?? foo bar}}</span>
    
    {{#if selection1}}
        doSomething1
    {{else}}
       {{#if selection2}}
           doSomething2
       {{/if}}
    {{/if}}