5

我正在尝试实现基于 MVVM 的单页应用程序,目前正在使用框架 Knockout.js 来处理 MVVM 的视图模型/视图部分。不过我很困惑,因为我为实现 Knockout 而查看的每个示例都涉及将整个视图模型保存到数据库中。这些示例是否缺少“模型”步骤,其中视图模型与数据层模型同步,模型进行验证/服务器同步。

我想在单个页面上有多个不同的模板/视图,每个都有不同的视图模型。我发现 knockout.js 缺少的另一件事是在不同视图之间同步单个模型(不是视图模型)。我认为让每个视图共享一个巨大的视图模型是没有意义的,所以我认为每个视图都有自己的视图模型,但每个视图模型将与几个应用程序范围模型所需的字段同步每个视图。

我正在处理的页面获取一个巨大的模型(30 多个字段,多层父/子关系),我认为让我的所有视图模型与这个模型同步是有意义的。我研究了 Knockback.js(它结合了 knockout.js 和骨干网),但是我最终重写了大多数函数,例如 fetch、set、save,因为页面正在从 API 获取数据(我可以'不只是与服务器来回同步整个模型)所以我决定反对它。

我的应用程序的视觉示例:

(模型层) M | 米

(视图模型/视图层)VM-V | 虚拟机-V | 虚拟机-V | 虚拟机-V


另一个例子

一个示例模型是 User = {firstName: "first", lastName: "last", ... }

一个视图模型只需要名字,另一个视图模型只需要姓氏
ViewModelA={firstName: app.User.firstName()}
ViewModelB={firstName: app.User.lastName()}

这样做是为模型和视图模型更改定义发布/订阅系统的唯一方法吗?这甚至是好的/可维护的架构吗?我在这里错过了一个基本概念吗?欢迎所有建议。

4

4 回答 4

5

如果我没看错的话,这里有很多问题都集中在如何使用 Knockout 构建 MVVM / SPA。正如您所指出的,有一些事情需要解决。一是如何在视图模型/视图对之间进行通信。

主视图模型 一种方法是让主视图模型作为@Tyrsius 的答案。你的 shell 可以有一个绑定更多可用数据的视图模型。主视图模型也可以编排子视图模型。如果你走这条路,那么你必须小心将外壳绑定到主视图模型,将内部绑定到 DOM 中的特定 HTML 元素。如果需要,主视图模型可以促进它们之间的通信。

解耦视图/视图模型对 另一种选择是使用视图模型/视图对而不使用主视图模型。每个视图都被加载到 DOM 的一个区域中并自行绑定。它们作为独立的单元,彼此分离。您可以使用 pub/sub 在两者之间进行对话,但如果您只需要一种通过 observables 同步数据的方法,Knockout 提供了许多选项。我喜欢的一个是让每个 viewmodel 表面模型对象。因此,视图有一个视图模型,它显示特定于视图的数据(来自模型)。如此多的视图模型可能以不同的方式显示相同的模型。因此,当视图更新视图模型属性(即在模型中)时,它会波及任何其他加载的也使用相同模型的视图模型。

DataContext 更进一步,您可以创建一个数据上下文模块来管理模型中的数据。您向 datacontext 询问模型(例如:客户列表),datacontext 检查是否已经将它们 cahced,如果没有,它会从 ajax 调用中获取它们。无论哪种方式都是从视图模型和模型中抽象出来的。datacontext 获取数据并将模型返回给视图模型。这样您就可以非常解耦,但您可以通过数据上下文共享数据(您的模型)。

我可以继续……但请告诉我这是否回答了你的问题。如果没有,很乐意回答任何其他细节。

** 免责声明:我正在建立一个关于 SPA 的 Pluralsight 课程(使用 Knockout 和这个策略):-)

于 2012-06-28T20:10:12.360 回答
2

这是一个现在很受欢迎的领域,所以我希望你会得到一些更好的答案,但这里就是这样。

该模型

是的,您绝对应该拥有数据的服务器端表示,这就是您的模型。这取决于您的服务器和数据库。对于 MVC3,这是您的实体模型。对于 Django 或 Ruby,您将定义数据库模型作为数据库设置的一部分。这部分取决于您的具体技术。但是再次,的,您应该有一个模型,并且服务器绝对应该执行数据验证。

应用程序(视图模型)

建议您的每个视图都有自己的视图模型。然后你的页面也可以有一个视图模型,如果你愿意的话,一个应用程序视图模型,它可以跟踪所有这些。如果你走这条路,应用程序视图模型应该负责在视图之间切换,并实现任何其他应用程序级别的逻辑(如哈希导航,另一种流行的单页工具)。这种层次结构非常重要,但并不总是那么简单。这将取决于您的应用程序的具体要求。您不仅限于一个平面视图模型。这不是唯一可能的方法。

特设示例:

​var ThingViewModel = function(name, data){
    this.name = ko.observable(name);
    //Additional viewmodel stuffs
};

var AppViewModel = function(initialData){
    //Process initial data    
    this.thing = new ThingViewModel(someName, someData); 

};

我现在正在做一个类似的项目,纯粹是为了学习(不是真实世界的应用程序),它托管在 GitHub 上,如果你想看看一些真实的例子。请注意,该dev分支目前领先于该master分支。我确信它包含一些不好的模式(请随时指出它们,我也在学习),但无论如何你也许可以从中学到一些东西。

于 2012-06-28T18:50:36.967 回答
1

我有一个同样复杂的解决方案,我正在将 WPF 应用程序改造成 Web 版本。WPF 版本处理复杂的域对象,它通过演示者模型绑定到视图。

在 web 版本中,我实现了简化且有些扁平化的服务器端视图模型,这些模型使用 Automapper 在域对象之间来回转换。然后,这些服务器端视图模型作为 JSON 来回发送到客户端,并使用映射插件映射到/映射到相应的 Knockout 视图模型(每个负责创建具有子映射选项的子代的可实例化函数)。

当我需要保存/验证我的 UI 时,我将全部或部分 Knockout 视图模型映射回纯 Javascript 对象,将其发布为 JSON,MVC 框架将其绑定回服务器端视图模型,这些会自动映射回域对象,由我们的域层验证并可能更新,然后返回并重新映射修改后的完整或部分图。

目前我只有一个主页,其中发生 Knockout 操作,但我预计像你一样,我最终会得到多个上下文,这些上下文需要处理相同的模型(我的域对象),根据我的不同视图模型拉取为不同的视图模型正在和他们一起做。

对此,我已经构建了服务器端视图模型目录等,以及我的 Knockout 视图模型的结构。到目前为止,这种方法运行良好。希望这可以帮助。

于 2012-06-29T04:46:17.520 回答
0

在一个项目期间,我开发了一个框架(它使用 KnockoutJS),它提供解耦的 View/ViewModel 对并允许在视图中实例化子视图。视图和子视图实例化的整个处理由框架提供。它的工作方式类似于 MVVM 和 WPF 中的 XAML。

看看http://visto.codeplex.com

于 2013-09-13T14:40:48.063 回答