Templates 什么';无逻辑模板(如小胡子)的优点是什么?

Templates 什么';无逻辑模板(如小胡子)的优点是什么?,templates,mustache,Templates,Mustache,最近,我遇到了一个声称是无逻辑模板的 然而,无法解释为什么它是以无逻辑的方式设计的。换句话说,无逻辑模板的优点是什么?它使模板更干净,并迫使您将逻辑保留在一个可以正确进行单元测试的地方。无逻辑模板是一个包含漏洞的模板,供您填充,而不是如何填充。逻辑放在别处,并直接映射到模板。这种关注点分离是理想的,因为这样就可以很容易地用不同的逻辑构建模板,甚至用不同的编程语言构建模板 从: 我们称之为“无逻辑”,因为有 没有if语句、else子句或 对于循环。相反,只有 标签。某些标记被替换为 价值,有些一文

最近,我遇到了一个声称是无逻辑模板的


然而,无法解释为什么它是以无逻辑的方式设计的。换句话说,无逻辑模板的优点是什么?

它使模板更干净,并迫使您将逻辑保留在一个可以正确进行单元测试的地方。

无逻辑模板是一个包含漏洞的模板,供您填充,而不是如何填充。逻辑放在别处,并直接映射到模板。这种关注点分离是理想的,因为这样就可以很容易地用不同的逻辑构建模板,甚至用不同的编程语言构建模板

从:

我们称之为“无逻辑”,因为有 没有if语句、else子句或 对于循环。相反,只有 标签。某些标记被替换为 价值,有些一文不值,而另一些则一文不值 一系列的值。本文件 解释不同类型的 胡子标签


换句话说,它可以防止你射中自己的脚。在旧的JSP时代,JSP文件中散布Java代码是非常常见的,这使得重构更加困难,因为代码分散

如果您通过设计阻止模板中的逻辑(如Mustach所做的),您将不得不将逻辑放在其他地方,这样您的模板将变得整洁


另一个优点是,您不得不从关注点分离的角度进行思考:您的控制器或逻辑代码必须在将数据发送到UI之前进行数据处理。如果您以后将模板切换到另一个模板(假设您开始使用不同的模板引擎),那么转换将很容易,因为您只需实现UI细节(记住,模板上没有逻辑)。

我觉得我几乎是孤独的,但我坚定地站在相反的阵营。我不认为在模板中混合业务逻辑就足以成为不充分使用编程语言的理由

无逻辑模板的通常论点是,如果您完全可以访问您的编程语言,您可能会在模板中混入没有位置的逻辑。我发现这类似于你应该用勺子切肉的推理,因为如果你用刀的话,你可能会割伤自己。这是非常正确的,但是如果你小心地使用后者,你会更有效率

例如,考虑以下模板片段:

{{name}}
    {{{#项目}
  • {{}}
  • {{/items}
我能理解这一点,但我发现以下(使用)更简单、更直接:

<%- name %>:
<ul>
<% _.each(items, function(i){ %>
  <li><%- i %></li>
<% }); %>
</ul>

也就是说,我确实理解无逻辑模板的优点(例如,它们可以与多种编程语言一起使用,而无需更改)。我认为这些其他优势非常重要。我只是不认为他们缺乏逻辑的本质是其中之一。

尽管这个问题已经过时并得到了回答,但我还是想补充我的2美分(这听起来可能像是在咆哮,但事实并非如此,这是关于限制以及当它们变得不可接受时)

模板的目标是呈现某些内容,而不是执行业务逻辑。现在,在不能在模板中完成您需要做的事情和模板中包含“业务逻辑”之间存在一条很细的界线。尽管我对胡子非常积极,并尝试使用它,但在相当简单的情况下,我最终无法做到我需要的

数据的“按摩”(使用公认答案中的词语)可能会成为一个真正的问题——甚至不支持简单的路径(handlebar.js解决的问题)。如果我有视图数据,并且每次我想要渲染一些东西时都需要调整它,因为我的模板引擎太有限了,那么这最终是没有帮助的。它还破坏了Mustach声称的部分平台独立性;我不得不到处重复按摩的逻辑

也就是说,在经历了一些挫折之后,在尝试了其他模板引擎之后,我们最终创建了自己的(…又一个…),它使用了受.NET Razor模板启发的语法。它在服务器上被解析和编译,并生成一个简单的、自包含的JS函数(实际上是作为RequireJS模块),可以调用该函数来“执行”模板,并返回一个字符串作为结果。brad给出的示例在使用我们的引擎时看起来是这样的(我个人认为与小胡子和下划线相比,它在可读性方面要高得多):


它没有任何业务逻辑,但它是可重用和可配置的,并且没有副作用。

我为无逻辑模板提出的最佳论据是,您可以在客户端和服务器上使用完全相同的模板。然而,你并不真的需要无逻辑的,只要有自己的“语言”。我同意那些抱怨胡子毫无意义的限制的人。谢谢,但我是一个大男孩,我可以保持我的模板清洁没有你的帮助

另一种选择是找到一种模板语法,该语法使用客户端和服务器都支持的语言,即服务器上的javascript,可以使用node.js,也可以使用js解释器和json,通过类似于Rubyracer的东西


然后,您可以使用类似haml.js的东西,它比目前提供的任何示例都要干净,效果非常好。

用一句话来说:无逻辑意味着模板引擎本身不那么复杂,因此占用的空间更小,它的意外行为方式也更少。

小胡子是无逻辑的吗

这不是:

{{#x}}
  foo
{{/x}}
{{^x}}
  bar
{{/x}}
很像这个

if x
  "foo"
else
  "bar"
end

这不是很类似于(阅读:几乎是一个定义)表示逻辑吗?

硬币的另一面是,在绝望地试图将业务逻辑排除在表示之外时,您
<table>
    <thead>
        <tr>
            @for (columns) {
                <th>@title</th>
            }
            @if (actions) {
                <th>Actions</th>
            }
        </tr>
    </thead>
    <tbody>
        @for (rows) {
            @partial Row({ row: ., actions: $.actions, columns: $.columns })
        }
    </tbody>
</table>
<tr id="@(row.id)">
    @for (var $col in columns) {
        <td>@row.*[name()=$col.property]</td>
    }
    @if (actions) {     
        <td>
        @for (actions) {
            <button class="btn @(id)" value="@(id)">@(name)...</button>
        }
        </td>
    }
</tr>
var html = table({
    columns: [
        { title: "Username", property: "username" },
        { title: "E-Mail", property: "email" }
    ],
    actions: [
        { id: "delete", name: "Delete" }
    ],
    rows: GetAjaxRows()
})
{{#x}}
  foo
{{/x}}
{{^x}}
  bar
{{/x}}
if x
  "foo"
else
  "bar"
end
"#{name}"
ul items.map (i) ->
  li i
<span data-bind="value: name"/>
<ul data-bind="foreach: items">
   <li data-bind="value: i"/>
</ul>
{{name}}:
<ul>
  {{#items}}
    <li>{{.}}</li>
  {{/items}}
</ul>
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
  <li><%- i %></li>
<% }); %>
</ul>
  <% for(var i = 0; i < items.length; i++) { %>
    <%= items[i] %>
  <% } %>
{{#x}}
  foo
{{/x}}
{{^x}}
  bar
{{/x}}
<script id="items-tmpl" type="text/template">
    <ul>
        <% for(var i = 0; i < obj.items.length; i++) { %>
            <%= innerTmpl(obj.items[i]) %>
        <% } %>
    </ul>
</script>

<script id="item-tmpl" type="text/template">
    <li>
        <%= name %>
    </li>
</script>

var tmplFn = function(outerTmpl, innerTmpl) {
    return function(obj) {
        return outerTmpl({obj: obj, innerTmpl: innerTmpl});
    };
};

var tmpl = tmplFn($('#items-tmpl').html(), $('#item-tmpl').html());
var context = { items: [{name:'A',{name:'B'}}] };
tmpl(context);