【问题标题】:Logical operator in a handlebars.js {{#if}} conditionalhandlebars.js 中的逻辑运算符 {{#if}} 条件
【发布时间】:2012-01-13 15:59:29
【问题描述】:

handlebars JS 中有没有办法将逻辑运算符合并到标准的 handlebars.js 条件运算符中?像这样的:

{{#if section1 || section2}}
.. content
{{/if}}

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

【问题讨论】:

  • 对于“and”逻辑,您可以执行嵌套 if 条件,但它很笨拙,并且无法帮助您处理 else“除非”或上述问题的任何“或”逻辑。跨度>

标签: javascript handlebars.js


【解决方案1】:

这可以通过使用块助手“作弊”来实现。这可能与开发 Handlebars 的人的意识形态背道而驰。

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 / Moustache 的无逻辑性质,但仍然很有用,谢谢!
  • 请注意,这根本不适用于绑定属性(读取,Ember 绑定)。文字值很好,但不能解析模型属性(使用 Ember 1.0.0-rc.8 和 Handlebars 1.0.0 测试),registerBoundHelper 无法处理 Handlebars 语法。解决方法是创建自定义视图:stackoverflow.com/questions/18005111/…
  • @BalaClark 真的没有逻辑吗?我的意思是它仍然有“if”语句——仅仅因为它们被故意削弱并不会改变哲学。
  • 我不明白为什么 AND / OR 不能成为 Handlebars 的一部分。它并不违背无逻辑的本质,因为已经有 IF、UNLESS 和 EACH ......
  • @StackOverflowed 限制您的选择/限制自己有助于遵循开发理念。凭借有效的开发理念,当您尝试解决它旨在解决的问题时,实现它的 API 不应该感到障碍。相反,它应该以一种奇怪的方式让人感觉有力量:)(有点像禁欲)。回到主题,Handlebars 的哲学是矛盾的,这个问题中描述的问题可以通过以下解决方案来解决,Handlebars API 的实现很差,或者这不是 Handlebars 旨在解决的问题。
【解决方案2】:

使解决方案更进一步。这会添加比较运算符。

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}}

咖啡脚本版本

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

【讨论】:

  • 别忘了'||''&amp;&amp;'。我添加了这些案例,它们非常有用。
  • 作为车把的菜鸟,不清楚的一件事是您必须将运算符作为字符串传递,否则编译器在标记您的模板时会出错。 {{#ifCond true '==' false}}
  • 我发现没有针对对象属性评估这些值。添加以下帮助v1 = Ember.Handlebars.get(this, v1, options)v2 = Ember.Handlebars.get(this, v2, options)
  • 但如果 v1 和 v2 也是一个条件,那么我该如何使用?例如:if(value == "a" || value == "b")
  • 你能用这个做一个 else if 吗?
【解决方案3】:

Handlebars 支持嵌套操作。如果我们以稍微不同的方式编写逻辑,这将提供很大的灵活性(和更简洁的代码)。

{{#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);
    }
});

【讨论】:

  • 请注意,这在 Ember 1.10 中的 HTMLBars 之前是不可能的。此外,如果您愿意,这些助手可以作为 Ember CLI 插件提供:github.com/jmurphyau/ember-truth-helpers
  • 这种方式,不执行options更好地保持if方法,更容易测试。谢谢!
  • 我们似乎已将 Lisp 内置到 Handlebars 中。
  • 您的 andor 助手只能使用 2 个参数,这不是您想要的。我设法重新设计了 andor 助手以支持两个以上的参数。将此单线用于andreturn Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);,并将此单线用于orreturn Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);
  • 一个little more advanced version 可以在每个运算符上接受多个参数。
【解决方案4】:

对于那些生活在边缘的人来说,把这个提升一个档次。

要点https://gist.github.com/akhoury/9118682 演示:下面的代码sn-p

车把助手:{{#xif EXPRESSION}} {{else}} {{/xif}}

使用任何表达式执行 IF 语句的助手

  1. EXPRESSION 是一个正确转义的字符串
  2. 是的,您需要正确地转义字符串文字或只是交替单引号和双引号
  3. 您可以访问任何全局函数或属性,即encodeURIComponent(property)
  4. 这个例子假设你将这个上下文传递给你的车把template( {name: 'Sam', age: '20' } ),注意age是一个string,只是为了我可以在这篇文章后面演示parseInt()

用法:

<p>
 {{#xif " name == 'Sam' && age === '12' " }}
   BOOM
 {{else}}
   BAMM
 {{/xif}}
</p>

输出

<p>
  BOOM
</p>

JavaScript:(它依赖于另一个助手——继续阅读)

 Handlebars.registerHelper("xif", function (expression, options) {
    return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
  });

车把助手:{{x EXPRESSION}}

执行 javascript 表达式的助手

  1. EXPRESSION 是一个正确转义的字符串
  2. 是的,您需要正确地转义字符串文字或只是交替单引号和双引号
  3. 您可以访问任何全局函数或属性,即parseInt(property)
  4. 本示例假设您将此上下文传递给您的车把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>

JavaScript:

这看起来有点大,因为为了清晰起见,我扩展了语法并对几乎每一行进行了注释

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">
  <div class="content">
    {{#each this}}
    <div class="person">
      <h1>{{x  "'Hi ' + firstName"}}, {{x 'lastName'}}</h1>
      <div>{{x '"you were born in " + ((new Date()).getFullYear() - parseInt(this.age, 10)) '}}</div>
      {{#xif 'parseInt(age) >= 21'}} login here:
      <a href="http://foo.bar?email={{x 'encodeURIComponent(email)'}}">
        	http://foo.bar?email={{x 'encodeURIComponent(email)'}}
        </a>
      {{else}} Please go back when you grow up. {{/xif}}
    </div>
    {{/each}}
  </div>
</script>

<div id="main"></div>

摩尔

如果要访问上层作用域,这个稍有不同,表达式是所有参数的JOIN, 用法:假设上下文数据如下所示:

// 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}}

Javascript:

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);
});

【讨论】:

  • 这很棒。车把无法告诉您该做什么:)
  • :) 谢谢,我稍微更新了gist 以添加更多好东西(与这个 SO 问题没有直接关系 - 但本着在车把模板中做你想做的事情的精神)但是,您应该注意限制,我还没有找到从表达式中访问“上层范围级别”的方法,假设您在每个范围内,{{#each}} ... {{xif ' ../name === this.name' }} {{/each}} ...但我仍在调查..
  • 找到了“上层范围访问”的解决方案,但使用了新的助手,请参阅更新的答案,{{z ...}}助手
  • @rickysullivan 尝试将您的 eval(expression); 替换为:eval('(function(){try{return ' + expression + ';}catch(e){}})();'); - 我知道这越来越难看,但想不出一个安全的方法来做到这一点 - 请注意,这不是执行起来非常“快”,我不会在大量迭代中这样做。
  • 对于 NodeJS 的使用,您可能希望使用更安全的 eval 解决方案,例如:npmjs.com/package/safe-eval 而不是 eval() 函数
【解决方案5】:

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

{{#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}}

编辑/注意:来自车把的网站:handlebarsjs.com 以下是虚假值:

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

【讨论】:

  • 不是真的,你不比较两个值,你只是确保它们都存在,它是不同的。
  • 实际上它评估它的方式与 javascript 相同,来自网站:“您可以使用 if 助手有条件地渲染一个块。如果它的参数返回 false、未定义、null、“”或 [] (一个“假”值),Handlebars 不会渲染块。”
  • 你说得对,我首先认为测试是比较两个值,而不是测试两者都存在。我的错,对不起。
  • 这不能正常工作。如果 cond1 为真而 con2 为假,则不会打印任何内容。
  • 嘿@TessaLau,我想我明白你来自哪里了。但是,如果您画出一个控制流,您会看到在第一行中将控制流移动到该条件。
【解决方案6】:

此处发布的所有答案的一个问题是它们不适用于绑定属性,即当所涉及的属性发生更改时,不会重新评估 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}}

【讨论】:

  • 如果您使用的是 Ember,这是合适的答案。您提到的其他解决方案将只传递密钥而不是值。顺便说一句,谢谢你,花了几个小时让我头疼。
  • 有没有人在 HTMLBars/Ember 1.10 中使用过这个? Ember.Handlebars.bind 似乎不再存在。
  • 我最初使用 registerBoundHelper 但是当它改变条件时它不会改变到 else 值并返回.. 这种方法适用于 ember 改变:) 它应该有更多的投票
【解决方案7】:

改进的解决方案基本上适用于任何二元运算符(至少数字、字符串不适用于 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);
    }
});

【讨论】:

  • 您将如何在模板中使用它?尤其是 options.fn 部分?
  • {{ifCond val1 '||' val2}}true{{else}}false{{/if}} 如果正确则返回 options.fn(true,ifCond 子句),否则返回 options.inverse(false,else 子句)。跨度>
  • 由于提到了关于脚本注入的警告,我强烈建议不要使用这个帮助程序。在大型代码库中,这很容易导致严重的安全问题
【解决方案8】:

如果您想检查多个条件,这里有一个解决方案:

/* 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}}

【讨论】:

    【解决方案9】:

    这是我使用的块助手的链接:comparison block helper。它支持所有标准运算符,并允许您编写如下所示的代码。真的很方便。

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

    【讨论】:

    • 这应该是获胜的选票。原生的和有意的。我几乎每次都发现,如果你正在编写一个新的助手,你就会想太多了。
    • @augurone 这不是本地助手。如果您点击链接,您会看到它是一个自定义的帮助器。
    • @gfullam 你说得对,我在 assemble 中使用了车把,它本身就包含这个助手。我的错。
    【解决方案10】:

    通过运行以下命令安装Ember Truth Helpers插件

    ember 安装 ember-truth-helpers

    您可以开始使用大多数逻辑运算符(eq、not-eq、not、and、or、gt、gte、lt、lte、xor)。

    {{#if (or section1 section2)}}  
    ...content  
    {{/if}}
    

    您甚至可以包含子表达式以更进一步,

    {{#if (or (eq section1 "section1") (eq section2 "section2") ) }}  
    ...content  
    {{/if}}
    

    【讨论】:

    • 感谢分享,这个简单的解决方案很有魅力。
    • 看起来这在没有 ember-truth-helpers 的情况下工作。或者像这样嵌入车把的东西。 2022 年入住
    • 是的。感谢您的提醒。似乎在this RFC 中逐渐讨论和实施。
    【解决方案11】:

    与 Jim 的回答类似,但我们也可以使用一点创造力来做这样的事情:

    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 );
    } );
    

    然后要使用它,我们会得到类似的东西:

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

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

    【讨论】:

      【解决方案12】:

      三元助手的另一种弯曲解决方案:

      '?:' ( condition, first, second ) {
        return condition ? first : second;
      }
      
      <span>{{?: fooExists 'found it' 'nope, sorry'}}</span>
      

      或者一个简单的合并助手:

      '??' ( first, second ) {
        return first ? first : second;
      }
      
      <span>{{?? foo bar}}</span>
      

      由于这些字符在车把标记中没有特殊含义,因此您可以随意将它们用作助手名称。

      【讨论】:

        【解决方案13】:

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

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

        【讨论】:

        • 那么你需要在上下文中添加一个函数吗?从上下文执行代码是一个安全漏洞,因为代码的来源可能是未知的。这可以被用于 XSS 攻击。
        • 是的,您需要将函数添加到上下文中。在设计糟糕的网站中,是的,这可能是安全漏洞。但在那种情况下,会有很多其他人。
        • 这是首选方式.. TY.
        【解决方案14】:

        很遗憾,这些解决方案都不能解决“OR”运算符“cond1 || cond2”的问题。

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

          {{#if cond1}} 采取行动 {{^}} {{#if cond2}} 采取行动 {{/如果}} {{/if}}

        它违反了 DRY 规则。那么为什么不使用 partial 来减少混乱

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

        【讨论】:

          【解决方案15】:

          我可以理解为什么您要在模板中执行大量不同比较的情况下创建一个帮助程序,但比较数量相对较少(甚至是一个,这正是我想到的这个页面放在首位),在视图渲染函数调用中定义一个新的车把变量可能会更容易,比如:

          在渲染时传递给车把:

          var context= {
              'section1' : section1,
              'section2' : section2,
              'section1or2' : (section1)||(section2)
          };
          

          然后在您的车把模板中:

          {{#if section1or2}}
              .. content
          {{/if}}
          

          为了简单起见,我提到这一点,也因为它是一个快速且有用的答案,同时仍符合 Handlebars 的无逻辑性质。

          【讨论】:

            【解决方案16】:

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

            https://npmjs.org/package/handlebars-helpers

            您可以通过wget http://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgz 下载它们并查看包的内容。

            您将能够执行{{#is number 5}}{{formatDate date "%m/%d/%Y"}} 之类的操作

            【讨论】:

            • 感谢@Cristian!这是一个很好的解决方案!
            【解决方案17】:

            AND/OR 的正确解

            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') (..) ) }}
            

            顺便说一句:请注意,这里给出的解决方案是不正确的,他没有减去最后一个参数,即函数名。 https://stackoverflow.com/a/31632215/1005607

            他最初的 AND/OR 是基于完整的参数列表

               and: function () {
                    return Array.prototype.slice.call(arguments).every(Boolean);
                },
                or: function () {
                    return Array.prototype.slice.call(arguments).some(Boolean);
                }
            

            有人可以改变这个答案吗?我只是浪费了一个小时试图在 86 人推荐的答案中解决问题。解决方法是过滤掉作为函数名称的最后一个 参数。 Array.prototype.slice.call(arguments, 0, arguments.length - 1)

            【讨论】:

              【解决方案18】:

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

              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);
                }
              });
              

              喜欢这个

              {{#if_or elem1 elem2}}
                {{elem1}} or {{elem2}} are present
              {{else}}
                not present
              {{/if_or}}
              

              如果您还需要能够有一个“或”来比较 function return values 我宁愿添加另一个返回所需结果的属性。

              模板毕竟应该是无逻辑的!

              【讨论】:

                【解决方案19】:

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

                Ember.js helper not properly recognizing a parameter

                【讨论】:

                  【解决方案20】:

                  刚刚从谷歌搜索中找到这篇关于如何检查一个字符串是否等于另一个字符串的帖子。

                  我在 NodeJS 服务器端使用 HandlebarsJS,但我也在前端使用相同的模板文件,使用浏览器版本的 HandlebarsJS 来解析它。这意味着如果我想要一个自定义助手,我必须在 2 个不同的地方定义它,或者为有问题的对象分配一个函数——太费劲了!!

                  人们忘记的是某些对象具有可在 mustache 模板中使用的继承函数。字符串的情况下:

                  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match

                  An Array containing the entire match result and any parentheses-captured matched results; null if there were no matches.

                  我们可以使用这个方法返回一个匹配数组,或者如果没有找到匹配则返回null。这是完美的,因为查看 HandlebarsJS 文档http://handlebarsjs.com/builtin_helpers.html

                  You can use the if helper to conditionally render a block. If its argument returns false, undefined, null, "", 0, or [], Handlebars will not render the block.

                  所以...

                  {{#if your_string.match "what_youre_looking_for"}} 
                  String found :)
                  {{else}}
                  No match found :(
                  {{/if}}
                  

                  更新:

                  在所有浏览器上测试后,这不适用于 Firefox。 HandlebarsJS 将其他参数传递给函数调用,这意味着当调用 String.prototype.match 时,似乎正在传递第二个参数(即根据上述文档调用 match 函数的 Regexp 标志)。 Firefox 认为这是对 String.prototype.match 的弃用,因此中断。

                  一种解决方法是为 String JS 对象声明一个新的功能原型,并使用它来代替:

                  if(typeof String.includes !== 'function') {
                      String.prototype.includes = function(str) {
                          if(!(str instanceof RegExp))
                              str = new RegExp((str+'').escapeRegExp(),'g');
                          return str.test(this);
                      }
                  }
                  

                  确保在运行 Handlebars.compile() 函数之前包含此 JS 代码,然后在模板中...

                  {{#your_string}}
                      {{#if (includes "what_youre_looking_for")}} 
                          String found :)
                      {{else}}
                          No match found :(
                      {{/if}}
                  {{/your_string}}
                  

                  【讨论】:

                  • 已为 Firefox 更新,这是我目前使用的
                  【解决方案21】:

                  您可以简单地使用如下所示的逻辑运算符来做到这一点:

                  {{#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}}
                  

                  关闭之前是否可以写下你的业务逻辑

                  【讨论】:

                    【解决方案22】:

                    这里我们有多个逻辑 && 和 || 的原版车把(和或):

                    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
                    

                    不太确定使用“and”和“or”是否“安全”...也许改用“op_and”和“op_or”之类的东西?

                    【讨论】:

                      【解决方案23】:

                      按照a-way-to-let-users-define-custom-made-bound-if-statementscustom bound helpers 这两个指南,我可以在stackoverflow 上的这篇文章中调整我的共享视图,以使用它而不是标准的#if 语句。这应该比仅仅在其中扔一个#if 更安全。

                      该要点中的自定义绑定助手非常出色。

                      <li>
                          <a href="{{unbound view.varProductSocialBlog}}">
                              {{#if-equal view.showDiv "true"}}<div>{{/if-equal}}<i class="fa fa-rss-square"></i>{{#if-equal view.showDiv "true"}}</div>{{/if-equal}}
                              {{#if-equal view.showTitle "true"}}Blog{{/if-equal}}
                          </a>
                      </li>
                      

                      我正在使用 ember cli 项目来构建我的 ember 应用程序。

                      本文发布时的当前设置:

                      DEBUG: -------------------------------
                      DEBUG: Ember      : 1.5.1
                      DEBUG: Ember Data : 1.0.0-beta.7+canary.b45e23ba
                      DEBUG: Handlebars : 1.3.0
                      DEBUG: jQuery     : 2.1.1
                      DEBUG: -------------------------------
                      

                      【讨论】:

                        【解决方案24】:

                        在 Ember.js 中,您可以在 if 块助手中使用 inline if helper。可以替换||逻辑运算符,例如:

                        {{#if (if firstCondition firstCondition secondCondition)}}
                          (firstCondition || (or) secondCondition) === true
                        {{/if}}
                        

                        【讨论】:

                          【解决方案25】:

                          您可以使用以下代码:

                          {{#if selection1}}
                              doSomething1
                          {{else}}
                             {{#if selection2}}
                                 doSomething2
                             {{/if}}
                          {{/if}}
                          

                          【讨论】:

                          • 请详细说明您的想法和过程,如果人们不了解上下文或对语言不熟悉,他们可能很难理解您的解决方案。
                          【解决方案26】:

                          您不能在车把模板中编写表达式,而是在 express.js 中编写所有逻辑(表达式)

                          app.js

                          res.render("view.hbs", {expression: section1 || section2})
                          

                          view.hbs

                          {{#if expression}}
                            <h1> My Expression Returned True </h1>
                          {{ else }}
                            <h2>My Expression Returned False</h2>
                          {{/if}} <!-- End IF -->
                          

                          【讨论】:

                            【解决方案27】:

                            这是我用于 ember 1.10 和 ember-cli 2.0 的方法。

                            // app/helpers/js-x.js
                            export default Ember.HTMLBars.makeBoundHelper(function (params) {
                              var paramNames = params.slice(1).map(function(val, idx) { return "p" + idx; });
                              var func = Function.apply(this, paramNames.concat("return " + params[0] + ";"))
                              return func.apply(params[1] === undefined ? this : params[1], params.slice(1));
                            });
                            

                            然后你可以像这样在你的模板中使用它:

                            // 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}}
                            

                            表达式的参数以p0p1p2 等形式传入,p0 也可以引用为this

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2022-10-15
                              • 2017-01-01
                              • 1970-01-01
                              • 2014-04-03
                              • 2013-10-22
                              • 1970-01-01
                              • 2016-11-20
                              • 1970-01-01
                              相关资源
                              最近更新 更多