理解Backbone.js中MVC的内部结构依赖性

时间:2011-07-12 05:07:19

标签: javascript backbone.js

我有点困惑w.r.t.设计MVC时的结构依赖性 - 所以我们有一个模型,集合和视图(我还没有使用控制器,但问题也适用于它)。现在谁有人参考以OO术语发言。因此,集合是一个模型列表,因此我们可以将其视为从集合到模型的一对多依赖。在一些示例代码中,我有时会看到对“模型”对象中的视图的引用以及视图中模型的引用。有时是视图中的集合。

在模型中,我有时会看到一个this.view,在视图中我会看到类似this.model.viewthis.model的内容,因此会产生混淆以澄清:)

那么什么是“正确”的依赖关系(如果有“正确的方式”)或者每个人都可以依赖于每个人(不要认为这是正确的)即,理想情况下谁应该依赖于谁在Backbone的MVC对象设计中?当我看到这些截然不同的例子时,从结果的角度来看,知道他们应该如何在结构上相关,这有点令人困惑:)作为一个菜鸟什么是开始构建我的依赖关系的“正确”方式 - 一旦我上升了学习曲线我可能会自己弄清楚,但首先,应该怎么做呢?类似UML的图表将是额外的奖励;)

另一个问题: 有时我会在同一段代码中看到两个视图:例如:着名的todo.js http://documentcloud.github.com/backbone/docs/todos.html

现在虽然我理解需要多个视图,但令人困惑的是它们有何不同?我的意思是'el'和'tagName'之间的区别是什么?如果其中任何一个缺席,视图的表现会有何不同?我的意思是在上面的链接中,一个视图使用'tagName'而另一个'el',我不确定它们是如何关联的(如果有的话)。

我已经仔细阅读了文档,但正如我所说的那样,我仍然在学习,所以即使有了所有资源,我也可能根本无法理解它的一部分,可能需要人工干预:)

1 个答案:

答案 0 :(得分:86)

由于Backbone.js不是这样的框架,因此没有任何单一的“正确”方法可以做任何事情。但是,实现中有一些提示可以帮助您理解。此外,您可以应用一些经过时间考验的通用代码组织实践。但我会先解释一下这些观点。

浏览

Backbone中的视图与特定的DOM元素绑定(这就是el属性的用途)。

如果在初始化视图时它具有el属性,则Backbone.js使其成为新视图实例的属性。否则,它会查找tagNameidclassName属性,创建相应的DOM对象,并将其分配给新视图实例的el属性。 (在the source中对此进行了解释。)如果甚至没有tagName,则默认情况下会创建<div>元素。

因此,您可以猜测为什么TodoViewAppView使用不同的方法。 #todoapp元素最初存在于HTML的页面上,因此AppView可以使用它。但是当创建一个todo项目的视图时,它还没有DOM元素;所以开发人员在Backbone的类上定义了tagName来自动创建一个列表项。 (在initialize()方法中手动操作并不困难,但Backbone会为您节省一些时间。)

通常,视图属于以下两类之一:模型实例的视图和集合的视图。 Backbone不强制它,但它建议它可能是您想要的:如果您使用collectionmodel选项实例化视图,它们成为新创建的视图实例的属性,因此您可以通过view.collectionview.model访问它们。 (例如,如果您使用foo选项实例化视图,则会将其放入view.options.foo。)

依赖关系

良好做法

这只是我的意见。

  • 依赖性越低越好。

  • 遵循MVC模式有很多优点。

    请注意,Backbone.js术语与MVC的经典术语不匹配。这是正常的,MVC!=一组类,其定义有所不同。它更像是“你应该拥有的理想”(引自What is MVC and what are the advantages of it?)。

MVC        | Backbone.js                 | What it does
Controller | View (mostly)               | Handles user interaction
View       | template rendered by a view | Displays the data
Model      | Model & Collection          | Represents the data, handles data access
  • 模型层通常不应依赖任何东西。在MVC中,model是您访问数据的地方。这与这些数据的呈现无关。

    在Backbone中,模型可以是某个集合的一部分,但这不是一个重度依赖(AFAIK,它只是有助于自动找出与此模型对应的API端点的URL。)

  • 在Backbone中,集合可能已分配相应的模型类,但这也不是必需的。

  • 在Backbone中,路由器通常依赖于更高级别的视图(如整个页面或页面部分的视图),以响应应用程序状态的变化来呈现它们。反过来,这些视图依赖于一些较低级别的视图,例如小部件/页面部分。这些视图可能取决于集合和其他更低级别的视图。反过来,这些可能取决于特定的模型实例。

作为一个例子(箭头表示“依赖于”关系类型):

           +-------------+              +---------------+   +------------+
State      |MainRouter   |       Data:  |ItemCollection |   |ItemModel   |
Control:   |-------------|              |---------------|   |------------|
           |             |              |/api/items     +-->|/api/items/*|
           |             |              |               |   |            |
           |             |              |               |   |            |
           +---+-+-------+              +---------------+   +------------+
               | +----------------+                  ^              ^
               v                  v                  |              |
           +-------------+   +-------------+         |              |
Page-level |AboutView    |   |AppView      |         |              |
views:     |-------------|   |-------------|         |              |
           | section     |   | section     |         |              |
           | role="main" |   | role="main" |         |              |
           +--+-+--------+   +--+-+-+------+         |              |
              | +---------------|-|-|----+           |              |
              |      +----------+ | +----|---------+ |              |
              v      v            v      v         v |              |
           +--------------+   +--------------+   +---+-----------+  |
Widget     |SidebarView   |   |HeaderView    |   |ItemListView   |  |
views:     |--------------|   |--------------|   |---------------|  |
           | aside        |   | header       |   | ul            |  |
           |              |   |              |   |               |  |
           |              |   |              |   |               |  |
           +--------------+   +--------------+   +-----------+---+  |
                                                             |      |
                                                             v      |
                                                           +--------+---+
                                                           |ItemAsLiView|
                                                           |------------|
                                                           | li         |
                                                           |            |
                                                           +------------+

请注意,您可以设置多个路由器,在这种情况下,事情可能会有所不同。

todos.js

在Todos示例中,开发人员决定Todo模型实例应该依赖于相应的TodoView实例。实例化TodoView时,它会在相应的模型实例上创建一个属性view并将其自身分配给它。因此some_todo_model.view可以访问它。但是,应该注意model.view仅在Todo模型的clear()方法中使用,以便在清除模型时删除视图实例。

我认为 特定的依赖关系不是必需的。但是,对于这么小的应用程序,它可能没问题。

我找不到在视图中访问this.model.view的任何示例,因此我无法对此发表评论。

另见