【问题标题】:MVVM with Knockout.js带有 Knockout.js 的 MVVM
【发布时间】:2012-06-30 07:03:10
【问题描述】:

我正在尝试实现基于 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()}

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

【问题讨论】:

    标签: javascript mvvm knockout.js


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 首先,很抱歉 John 和 @Tysirius 的回复延迟,我上周接到了另一个项目。我真的很喜欢你建议的解耦 V/VM 结构。无论您在 SPA 中的哪个“页面”上,我都喜欢整体模型持续存在的想法。本质上,我的解释是我有一个模型,它有 10 个字段(现在都是 ko.observable()),然后是多个与该模型的部分表示同步的视图模型(只有少数字段), “涟漪”效果非常好。
    • 嗨,约翰,我在阅读了您关于 SPA KnockoutJs 模板的博客后发现了这篇文章。在模板中有一个表单标签已提交:addTodo 然后进行服务器往返,我一直在尝试通过单击按钮而不是往返来执行此操作,即。简单的推送让我很困惑——你知道我如何从数据上下文中调用 todoList.prototype.addTodo 函数吗?或者这是一个坏主意?顺便说一句,很棒的样本!
    • @MikeW 我没有关注。听起来你想要一个按钮来调用一个函数。使用点击绑定来执行此操作并在视图模型中调用该函数。然后,视图模型应该进行您想要的任何数据上下文调用。不要将数据上下文耦合到视图。有意义吗?
    【解决方案2】:

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

    模型

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

    应用程序(ViewModel)

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

    特设示例:

    ​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); 
    
    };
    

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

    【讨论】:

    • 您好! - 回复:您关于“您绝对应该拥有数据的服务器端表示”的观点,这是否意味着您的视图模型的每次更改都应该首先通过服务器?
    • 绝对不是!我的意思是模型类应该存在于服务器上,因为服务器将这些数据持久化(通常保存到数据库中),并且服务器必须使用它。淘汰视图模型操作应尽可能地保留在客户端上
    【解决方案3】:

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

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

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

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

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

    【讨论】:

    • 感谢您的回答,我还没有开始 JSON 映射,但我相信这会派上用场!
    【解决方案4】:

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

    看看http://visto.codeplex.com

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-25
      • 2014-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多