5

Логические операторы в условии {{#if}} Handlebars.js

13

Существует ли способ в Handlebars JS использовать логические операторы в стандартном условном операторе Handlebars.js? Например, что-то вроде этого:

{{#if section1 || section2}}
.. контент
{{/if}}

Я понимаю, что могу написать свой собственный хелпер, но сначала хотел бы убедиться, что не изобретаю колесо заново.

5 ответ(ов)

5

Это возможно с помощью "обмана" при использовании блочного помощника. Это, вероятно, противоречит идеологии людей, разработавших Handlebars.

Вот пример, как это можно реализовать:

Handlebars.registerHelper('ifCond', function(v1, v2, options) {
  if(v1 === v2) {
    return options.fn(this);
  }
  return options.inverse(this);
});

Затем вы можете использовать этот помощник в вашем шаблоне следующим образом:

{{#ifCond v1 v2}}
    {{v1}} равен {{v2}}
{{else}}
    {{v1}} не равен {{v2}}
{{/ifCond}}

Таким образом, вы сможете проверять условия внутри ваших шаблонов, что значительно увеличивает гибкость при работе с Handlebars.

5

В этой записи мы продолжаем работу с Handlebars, добавляя оператор сравнения в наш хелпер.

Вот пример кода, который регистрирует хелпер ifCond, позволяющий использовать различные операции сравнения в шаблонах Handlebars:

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 '==', '==='
            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

Таким образом, вы можете легко добавлять логику сравнения в свои шаблоны Handlebars, что сделает их более динамичными и гибкими.

2

Handlebars поддерживает вложенные операции, что предоставляет большую гибкость (и более чистый код), если мы немного иначе организуем нашу логику.

Например, можно использовать следующий код:

{{#if (or section1 section2)}}
.. контент
{{/if}}

На самом деле, можно добавить всевозможную логику:

{{#if (or 
        (eq section1 "foo")
        (ne section2 "bar"))}}
.. контент
{{/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);
    }
});

Эти вспомогательные функции позволят вам создавать более сложные условия в ваших шаблонах Handlebars, что сделает ваш код более компактным и понятным.

0

Есть простой способ сделать это без написания вспомогательной функции... Все можно сделать прямо в шаблоне.

{{#if cond1}}   
  {{#if cond2}}   
    <div> и условие выполнено</div>  
  {{/if}}
{{else}}   
  <div> оба условия не были истинными</div>  
{{/if}}

Редактирование: В свою очередь, вы можете использовать логическое "или", сделав это:

{{#if cond1}}  
  <div> или условие выполнено</div>    
{{else}}   
  {{#if cond2}}  
    <div> или условие выполнено</div>  
  {{else}}      
    <div> ни одно из условий не было истинным</div>    
  {{/if}}  
{{/if}}

Редактирование/Примечание: С сайта handlebarsjs.com: вот какие значения считаются "ложными":

Вы можете использовать вспомогательную функцию if для условного рендеринга блока. Если его аргумент возвращает false, undefined, null, "" или [] (ложное значение), тогда любое 'cond' (например, cond1 или cond2) не будет считаться истинным.

0

Вот улучшенное решение, которое работает с любым бинарным оператором (по крайней мере, с числами; строки могут работать не так хорошо с 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:
            // Используйте eval с осторожностью, особенно с пользовательским вводом
            try {
                const result = eval(`${v1} ${operator} ${v2}`);
                return result ? options.fn(this) : options.inverse(this);
            } catch (e) {
                console.warn("Ошибка выполнения eval:", e);
                return options.inverse(this);
            }
    }
});

Это решение предоставляет возможность использовать различные бинарные операторы в шаблонах Handlebars. Тем не менее, будьте осторожны с использованием eval, особенно если вводят данными пользователи, поскольку это может привести к уязвимостям типа "вставка скриптов" (XSS). Лучше использовать заранее определенные операторы, чтобы избежать подобных рисков.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь