handlebars.js {{#if}}中的逻辑运算符

handlebars JS中是否可以将逻辑运算符合并到标准handlebars.js条件运算符中?像这样:

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

我知道我可以编写自己的帮助程序,但是首先我想确保自己不会重新发明轮子。

小卤蛋村村2020/03/12 20:41:26

这是我用于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

TomProSam2020/03/12 20:41:26

在Ember.js中,可以在if阻止帮助程序中使用内联if帮助程序。它可以代替||逻辑运算符,例如:

{{#if (if firstCondition firstCondition secondCondition)}}
  (firstCondition || (or) secondCondition) === true
{{/if}}
十三JimHarry2020/03/12 20:41:26

按照这两个指南,让用户定义自定义绑定if语句自定义绑定帮助器,我能够在stackoverflow上的这篇文章中调整我的共享视图,以使用它代替标准的#如果声明。这不仅比在其中扔一个#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: -------------------------------
神无阿飞古一2020/03/12 20:41:26

在这里,我们有用于多个逻辑&&和||的香草车把。(和):

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”之类的东西?

猪猪GO2020/03/12 20:41:26

对于那些在比较对象属性方面遇到问题的人,可以在助手内部添加此解决方案

Ember.js帮助器无法正确识别参数

LEYTom2020/03/12 20:41:26

我找到了一个由CoffeeScript制作的npm软件包,其中有许多令人难以置信的有用的辅助工具。查看以下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"}}

LEYPro达蒙2020/03/12 20:41:26

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

余烬安装ember-truth-helpers

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

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

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

{{#if (or (eq section1 "section1") (eq section2 "section2") ) }}  
...content  
{{/if}}
泡芙阿飞斯丁2020/03/12 20:41:26

与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”。

阿飞番长2020/03/12 20:41:26

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

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

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

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

{{#if cond1}}
    {{> subTemplate}}
{{^}}
    {{#if cond2}}
        {{> subTemplate}}
    {{/if}}
{{/if}}
2020/03/12 20:41:26

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

{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}
小宇宙小小米亚2020/03/12 20:41:26

改进的解决方案,基本上可以与任何二进制运算符一起使用(至少数字,字符串不能与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);
    }
});
达蒙斯丁2020/03/12 20:41:26

车把支持嵌套操作。如果我们将逻辑编写得有些不同,这将提供很大的灵活性(和更简洁的代码)。

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

实际上,我们可以添加各种逻辑:

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

只需注册这些助手:

Handlebars.registerHelper({
    eq: function (v1, v2) {
        return v1 === v2;
    },
    ne: function (v1, v2) {
        return v1 !== v2;
    },
    lt: function (v1, v2) {
        return v1 < v2;
    },
    gt: function (v1, v2) {
        return v1 > v2;
    },
    lte: function (v1, v2) {
        return v1 <= v2;
    },
    gte: function (v1, v2) {
        return v1 >= v2;
    },
    and: function () {
        return Array.prototype.slice.call(arguments).every(Boolean);
    },
    or: function () {
        return Array.prototype.slice.call(arguments, 0, -1).some(Boolean);
    }
});