所有视图逻辑都应该放在模板中吗

Should all the view logic go in templates?

本文关键字:视图      更新时间:2024-01-16

例如,当视图的模型不是新的(有id)时,我需要禁用每个输入。

我可以做:

if(!view.model.isNew()) { view.$('input, select, textarea').prop('disabled', true); }

或者我可以在我的模板中的每一个输入上做一个"如果":

<input type="text" {{# if model.id }}disabled{{/ if }}/>

如果我们遵循MVC(或MVP)模式,我想第二种方法将是最好的,因为视图逻辑在视图中。然而,如果我采用这种方法并决定更改禁用输入的条件,我需要为每个模板中的每个输入更改它。如果我在JS代码中离开,那么只有一个地方可以更改。

这只是一个例子,但我在很多事情上都有类似的困境。希望你能得到答案。

干杯!

根据您的问题,我想说您遇到这个一般性问题可能有两个相关的原因-

  1. 你只使用主干,而不是像Marionette或Chaplin那样的框架
  2. 你的观点"太大",试图将太多的材料纳入一个单一的观点中

我几乎从不在模板中包含逻辑,这是因为我几乎从不需要。这是因为写了很多非常小的视图将它们拼凑在一起形成大视图

在1-2行代码中使用Marionette定义一个有用的视图并不罕见,这为您提供了很大的灵活性来创建非常小、高效的视图。制作大量小视图的缺点是要编写大量代码,而且可能会变得难以维护,但Marionette使这一缺点相对微不足道。Marionette只花了我几天的时间就掌握了窍门,我强烈建议将它集成到您的主干应用程序中,以解决这个问题。

当你的观点很大,并且试图做得太多时,你最终会遇到你所描述的问题——你必须对它们进行太多修改以满足你的特定需求,你的代码就会变得丑陋而难以阅读。当你有很多小视图时,它们的响应能力很强,几乎不需要定制。

我认为,你问题中的例子是一个边界线案例。我的直觉是创建两个完全独立的视图,并在以下伪代码下运行它们:

editableView = { //definition }}
disabledView = { //definition }}
if (newModel)
    editableView.render()
else
    disabledView.render()

这是我的直觉,因为我敢打赌,除了输入是否可编辑之外,视图之间还有其他差异。即使现在还没有,几个月后你可能会发现你的需求已经改变,你想融入一些变化。我建议的方法允许您将这些更改直接放入适当的视图中,而不必担心在单个视图中对其进行逻辑运算,并决定该逻辑是属于模板还是视图。

如果绝对确定两个视图之间的唯一区别将是输入是否可编辑,并且您的需求在未来不会改变,那么可能您会考虑用相同的视图渲染它们。如果是这种情况,出于您确定的原因,我建议您将逻辑放在javascript中,而不是放在模板中。但正如我所说,你的例子确实是一个边缘案例,在大多数情况下,我认为你会发现缩小你的视图范围确实会帮助你看到你的"模板逻辑"属于哪里。

注意:我在这个答案中谈到了很多关于马里内特的内容,但我也提到卓别林是上面的另一个选项。我对卓别林没有太多经验,但你可能想把它当作一种木偶戏的替代品。

我更喜欢在模板中实现视图逻辑:

  1. 它更容易更改和阅读
  2. 对id、元素等的任何依赖都可以在模板中实现
  3. 列出项目
  4. 复杂的逻辑可以在提线木偶的templateHelper或Backbone的serializeData中实现,而不依赖于模板或视图的内容
  5. 还可以使用HandlebarHelper实现复杂的逻辑

代码中视图逻辑的缺点是:

  1. 如果选择器(id、类等)发生更改,则必须更改或查看所有视图
  2. 如果视图被重新呈现,则必须再次应用逻辑

也许您正在寻找的是演示者(又名装饰者)。

与其直接将模板发送到模型,不如考虑通过演示者发送,这样您就可以构造输入字段的属性。类似这样的东西:

present = function(model) {
  return {
    inputAttributes: model.isNew() ? 'disabled' : '',
    id: model.id,
    name: 'Foobar'
  }
}
template(present(model));

然后在您的模板中:

<input type="text" {{inputAttributes}}>