最近,我遇到了mustache,声称是无逻辑模板。
然而,没有解释为什么它以无逻辑方式设计。换句话说,无逻辑模板的优势是什么?
答案 0 :(得分:101)
换句话说,它可以防止你在脚下射击。在旧的JSP时代,使用Java代码散布JSP文件是很常见的,这使得重构变得更加困难,因为你的代码已经分散了。
如果您在模板设计(如胡子一样)中阻止了逻辑,那么您将不得不将逻辑放在别处,这样您的模板就会变得整洁。
另一个优点是您不得不考虑关注点分离:在将数据发送到UI之前,您的控制器或逻辑代码必须执行数据按摩。如果您稍后将模板切换为另一个模板(假设您开始使用不同的模板引擎),则转换将很容易,因为您只需要实现UI详细信息(因为模板上没有逻辑,请记住)。
答案 1 :(得分:64)
我觉得在我看来我几乎是孤独的,但我坚定地站在对面的阵营中。我不相信模板中可能混合业务逻辑就足以让您不使用编程语言的全部功能。
无逻辑模板的常见理由是,如果您具有对编程语言的完全访问权限,则可能会混合使用模板中没有位置的逻辑。我发现这类似于推理,你应该用勺子切肉,因为如果你使用刀可以割断自己。这是非常正确的,但是如果你使用后者,你将会更有效率,尽管很小心。
例如,请使用mustache考虑以下模板代码段:
{{name}}:
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
我能理解这一点,但我发现以下(使用underscore)更加简单直接:
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
<li><%- i %></li>
<% }); %>
</ul>
话虽如此,我确实理解无逻辑模板具有优势(例如,它们可以与多种编程语言一起使用而无需更改)。我认为这些其他优势非常重要。我只是不认为他们的逻辑性质就是其中之一。
答案 2 :(得分:25)
胡子是无逻辑的?
不是这个:
{{#x}}
foo
{{/x}}
{{^x}}
bar
{{/x}}
与此非常相似?
if x
"foo"
else
"bar"
end
并不是 非常类似于(读取:几乎是定义)表示逻辑?
答案 3 :(得分:13)
无逻辑模板是一个模板,其中包含供您填充的孔,而不是填充它们的方式。逻辑放在别处并直接映射到模板。这种关注点的分离是理想的,因为模板可以很容易地用不同的逻辑构建,甚至可以用不同的编程语言构建。
我们称之为“无逻辑”,因为那里 不是if语句,否则是条款,或者 for循环。相反,只有 标签。有些标签被替换为 价值,一些没什么,和其他人一样 一系列的价值观。这个文件 解释了不同类型的 小胡子标签。
答案 4 :(得分:11)
它使您的模板更清晰,并且它迫使您将逻辑保留在可以进行适当单元测试的位置。
答案 5 :(得分:10)
硬币的另一面是,为了将业务逻辑排除在演示之外,您最终会在模型中放置大量的表示逻辑。一个常见的例子可能是您希望在表中的交替行上放置“奇数”和“偶数”类,这可以通过视图模板中的简单模运算符来完成。但是如果您的视图模板不允许您这样做,那么在您的模型数据中,您不仅要存储奇数或偶数行,而且取决于模板引擎的限制,您甚至可能需要污染模型使用实际CSS类的名称。视图应与模型分开,全程。但是模型也应该是View不可知的,而这就是许多这些“无逻辑”模板引擎让你忘记的东西。逻辑在两个地方都有,但你必须明白实际做什么来正确地决定它的去向。是演示问题还是业务/数据问题?为了获得100%纯净的观点,污染只会落在另一个不太明显但同样不适当的地方。
There's a growing movement back in the other direction,希望事情能够在更合理的中间地带中心。
答案 6 :(得分:5)
我为无逻辑模板提出的最佳论点是,您可以在客户端和服务器上使用完全相同的模板。然而,你真的不需要逻辑,只有一个拥有它自己的“语言”。我同意那些抱怨小胡子毫无意义地限制的人。谢谢,但我是一个大男孩,我可以在没有你帮助的情况下保持我的模板清洁。
另一个选择是找到一个模板语法,它使用客户端和服务器都支持的语言,即使用node.js在服务器上的javascript,或者你可以通过类似therubyracer的东西使用js解释器和json。
然后你可以使用像haml.js这样的东西,它比目前提供的任何例子都要干净得多。
答案 7 :(得分:5)
这种对话感觉就像中世纪的僧侣会争论有多少天使可以放在别针的末端。换句话说,它开始感到宗教,徒劳和错误的集中。
随之而来的是迷你咆哮(随意忽略):
如果您不想继续阅读..我对上述主题的简短回答是: 我不同意无逻辑模板。我认为它是一种极端主义的编程形式。 :-): - )
现在我的咆哮继续如火如荼: - )
我认为当你把很多想法发挥到极致时,结果就变得荒谬了。有时(即本主题)问题是我们将“错误”的想法推向了极致。
从视图中删除所有逻辑是“ludicroous”和错误的想法。
退一步。
我们需要问自己的问题是为什么要删除逻辑?这个概念显然是separation of concerns。保持视图处理尽可能与业务逻辑分开。为什么这样?它允许我们交换视图(针对不同的平台:移动,浏览器,桌面等),它允许我们更容易地交换控制流,页面序列,验证更改,模型更改,安全访问等。当逻辑是从视图中删除(尤其是Web视图),它使视图更具可读性,因此更易于维护。我明白并同意了。
然而,最重要的焦点应该是分离关注点。不是100%逻辑少的视图。视图中的逻辑应该与如何呈现“模型”相关。就我而言,视图中的逻辑非常好。您可以拥有非业务逻辑的视图逻辑。
是的,在我们编写JSP,PHP或ASP页面的那一天,很少或根本没有代码逻辑和视图逻辑的分离,这些Web应用程序的维护是一个绝对的噩梦。相信我,我知道,我创造并保持了一些这些怪物。正是在维护阶段,我真正理解(内心)我和同事的错误方式。 :-): - )
所以来自高层(行业权威人士)的法令变成了,你必须使用像前视图控制器(派遣给处理者或行动[选择你的网络框架])的东西来构建你的网络应用程序,你的观点必须不包含任何代码。这些观点将成为愚蠢的模板。
所以我总体上同意上述观点,不是针对法令条款的细节,而是法令背后的动机 - 这是希望在观点和商业逻辑之间分离关注点。
在我参与的一个项目中,我们试图将无逻辑的观点理念追溯到荒谬的极端。我们有一个自行开发的模板引擎,它允许我们在html中渲染模型对象。这是一个简单的基于令牌的系统。一个非常简单的原因是可怕的。有时在我们必须决定的视图中,我应该显示这个HTML的小片段..或者不是。决定通常基于模型中的某些值。当你在视图中完全没有逻辑时,你是如何做到的?嗯,你不能。我和我们的建筑师有一些关于此的主要论点。编写我们观点的前端HTML人员在面对这种情况时完全陷入困境,并且非常紧张,因为他们无法实现其他简单的目标。所以我在模板引擎中引入了一个简单的IF语句的概念。我无法向你描述随之而来的安慰和平静。我们的模板中使用简单的IF-Statement概念解决了问题!突然间,我们的模板引擎变得很好。
那么我们是如何陷入这种愚蠢的压力状况的呢?我们专注于错误的目标。我们遵循规则,您的观点中不得有任何逻辑。那是错的。我认为“经验法则”应该是,尽量减少视图中的逻辑量。因为如果你不这样做,你可能会无意中让业务逻辑蔓延到视图中 - 这违反了关注点的分离。
我理解当你声明“你必须在视图中没有逻辑”时,很容易知道你什么时候成为一个“好”的程序员。 (如果这是你善良的衡量标准)。现在尝试使用上述规则实现中等复杂度的Web应用程序。它不是那么容易做到的。
对我来说,观点中的逻辑规则并不是那么明确,坦率地说,这就是我想要的地方。
当我在视图中看到很多逻辑时,我会发现代码异味,并尝试从视图中消除大部分逻辑 - 我尝试确保业务逻辑生活在其他地方 - 我试图将问题分开。但是,当我开始与那些说我们必须从视图中移除所有逻辑的人聊天时,对我来说,只是因为我知道你可能最终会遇到如上所述的情况。 / p>
我完成了我的咆哮。 : - )
干杯,
大卫
答案 8 :(得分:4)
用一句话来说:无逻辑意味着模板引擎本身不那么复杂,因此占用空间更小,并且行为意外的方式也更少。
答案 9 :(得分:3)
即使这个问题已经陈旧并且已经回答了,我想加上我的2¢(听起来像是一个咆哮,但事实并非如此,这是关于限制的,当它们变得不可接受时)。
模板的目标是渲染某些东西,而不是执行业务逻辑。现在,在模板中无法完成您需要做的事情和在其中具有“业务逻辑”之间存在一条细线。即使我对Mustache非常积极并尝试使用它,但最终我无法在非常简单的情况下做我需要的。
数据的“按摩”(使用接受的答案中的单词)可能成为一个真正的问题 - 甚至不支持简单的路径(Handlebars.js解决的问题)。如果我有查看数据,我需要调整每次我想渲染的东西,因为我的模板引擎太限制,那么这最终没有帮助。它打败了胡子声称自己的部分平台独立性;我必须在任何地方复制按摩逻辑。
也就是说,经过一些挫折之后,在尝试其他模板引擎之后,我们最终创建了自己的(...另一个......),它使用了受.NET Razor模板启发的语法。它在服务器上进行解析和编译,并生成一个简单的,自包含的JS函数(实际上是RequireJS模块),可以调用它来“执行”模板,返回一个字符串作为结果。使用我们的引擎时,brad给出的样本看起来像这样(我个人发现,与Mustache和Underscore相比,它的读取性能远远超过了它):
@name:
<ul>
@for (items) {
<li>@.</li>
}
</ul>
在使用Mustache调用partials时,另一个无逻辑限制让我们感到震惊。虽然Mustache支持partials,但是不可能首先自定义要传递的数据。因此,我不会创建模块化模板并重复使用小块,而是最终会使用重复的代码来创建模板。
我们通过实现受XPath启发的查询语言解决了这个问题,我们称之为JPath。基本上,我们不使用/遍历子项,而是使用点,不仅支持字符串,数字和布尔文字,还支持对象和数组(就像JSON一样)。该语言是无副作用的(这是模板必须的),但允许通过创建新的文字对象来“按摩”数据。
假设我们想要呈现一个带有cusomizable标头的“数据网格”表,并链接到行上的操作,然后使用jQuery动态添加行。因此,如果我不想复制代码,那么行必须是部分的。如果某些其他信息(例如要呈现的列)是视图模型的一部分,并且每行上的那些操作都是相同的,那就是故障开始的地方。这是使用我们的模板和查询引擎的一些实际工作代码:
表格模板:
<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>
从JS代码调用:
var html = table({
columns: [
{ title: "Username", property: "username" },
{ title: "E-Mail", property: "email" }
],
actions: [
{ id: "delete", name: "Delete" }
],
rows: GetAjaxRows()
})
它没有任何业务逻辑,但它是可重用和可配置的,而且它也没有副作用。
答案 10 :(得分:1)
以下是渲染列表的3种方式,包括字符计数。除了第一个和最短的一个都是无逻辑的模板语言..
CoffeeScript(使用Reactive Coffee构建器DSL) - 37个字符
"#{name}"
ul items.map (i) ->
li i
淘汰赛 - 100个角色
<span data-bind="value: name"/>
<ul data-bind="foreach: items">
<li data-bind="value: i"/>
</ul>
把手/小胡子 - 66个字符
{{name}}:
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
下划线 - 87个字符
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
<li><%- i %></li>
<% }); %>
</ul>
我认为,无逻辑模板的承诺是,具有更广泛技能的人将能够管理无逻辑模板而无需自己动手。但是,您在上面的示例中看到的是,当您向基于字符串的标记添加最小逻辑语言时,结果会更复杂,而不是更少。此外,你看起来像是在做老式的PHP。
显然,我并不反对将“业务逻辑”(大量计算)保留在模板之外。但我认为,通过为显示逻辑而不是一流语言提供伪语言,可以支付价格。不仅仅是打字更多,而是一个令人发指的上下文切换组合,有人需要阅读它。
总之,我没有看到逻辑较少的模板的逻辑,所以我说他们的优势对我来说没有,但我尊重社区中的许多人看到的不同:)
答案 11 :(得分:1)
我同意布拉德:underscore
风格更容易理解。但我必须承认,语法糖可能不会让所有人满意。如果_.each
有些令人困惑,您可以使用传统的for
循环。
<% for(var i = 0; i < items.length; i++) { %>
<%= items[i] %>
<% } %>
如果您可以回退到标准结构,例如for
或if
,那总是很好。只需使用<% if() %>
或<% for() %>
,而Mustache
使用if-then-else
的某种新词(如果您没有阅读文档则会感到困惑):
{{#x}}
foo
{{/x}}
{{^x}}
bar
{{/x}}
当您可以轻松地实现嵌套模板时,模板引擎非常棒(underscore
样式):
<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);
基本上,您将内部tmpl作为上下文的属性传递。并相应地调用它。甜蜜:))
顺便说一句,如果您感兴趣的唯一内容是模板引擎,请使用独立模板实现。缩小(4个长行)时仅900字符:
答案 12 :(得分:0)
使用无逻辑模板的主要优点是: