这篇文章很老了,但我们今天早些时候正在审查它,所以以防其他人遇到它:
对我来说,我真的看到了两个不同的问题:
- 数据获取机制和结果视图渲染应该发生在路由器还是视图中?
- 视图应该期待已经解析的模型,还是应该响应可能仍在加载的模型?
我们处理它的方式与一些个人喜好混合在一起:
- 两者都没有,尽管我会更靠近路由器。路由器应该处理路由,视图应该处理查看,而其他东西应该处理模型/集合获取逻辑的机制和工作流程。我们称其为控制器,路由器基本上委托给它。
- 正如尤里所暗示的,“有时”是现实。我认为这可能是个案决定,但最终应该是控制器和视图之间的合同,而不是路由器/视图之间的合同。
我喜欢 Yuri 的要点,有几个注意事项(缩进的项目符号):
- 路由器只知道将用户发送到哪里
- 外部视图只知道用户应该查看什么(给定它的数据)
- 假设外部视图特定于内部视图的用例并且由另一个视图“拥有”(用于清理)
- 否则对于通用容器(例如渲染到“主”位置),我们发现拥有一个管理页面上某个“部分”的视图的组件很有用 - 我们称之为渲染器
- 内部视图只知道如何只显示它们的一小部分(并且可以在其他地方使用)
- 并且渲染功能始终显示正确的内容。
Renderer 的主要原因是处理与该部分相关的事情,例如清理现有视图以避免重影视图,在渲染时滚动到顶部(我们的 MainContentRenderer 会这样做),或者在这种情况下显示一个微调器。
一个可能看起来像的伪代码示例,用于:
- 通用内容目标“主要”(如果它是特定于用例的,根据 Yuri 的示例,使用 ComponentView 可能会更好,具体取决于您的视图生命周期管理策略)
- 我们必须获取并等待的模型
- 接受已加载模型的视图
路由器:
routes: {
"profile": "showProfile"
},
showProfile: function() {
return new ProfileController().showProfile();
}
配置文件控制器:
showProfile: function() {
//simple case
var model = new Model();
var deferredView = model.fetch.then(function() {
return new View(model);
};
MainContentRenderer.renderDeferred(deferredView);
}
主要内容渲染器:
var currentView;
renderDeferred: function(deferredView) {
showSpinner();
deferredView.then(function(view) {
this.closeSpinner();
this.closeCurrentView();
this.render(view);
}
},
render: function(view) {
currentView = view;
$('#main-content').html(view.render().el);
}
closeCurrentView: function() {
if (currentView and currentView.close()) {
currentView.close();
}
}
引入控制器还具有可测试性的额外好处。例如,我们有复杂的规则来执行围绕 URL 管理的搜索、在结果视图和新搜索视图之间进行选择,以及在缓存的“最后”搜索结果和执行新搜索之间进行选择。我们对控制器进行了 Jasmine 测试,以验证所有流逻辑是否正确。它还提供了一个隔离的地方来管理这些规则。