【问题标题】:KnockOutJS - Multiple ViewModels in a single ViewKnockOutJS - 单个视图中的多个 ViewModel
【发布时间】:2012-03-06 19:36:29
【问题描述】:

我认为我的应用程序现在变得非常大,太大而无法使用单个 ViewModel 处理每个视图。

所以我想知道创建多个 ViewModel 并将它们全部加载到一个 View 中会有多困难。请注意,我还需要能够将 X ViewModel 数据传递到 Y ViewModel 数据中,因此各个 ViewModel 需要能够相互通信或至少能够相互通信互相了解。

例如,我有一个<select> 下拉列表,该选择下拉列表有一个选择状态,它允许我将<select> 中选定项目的 ID 传递给单独 ViewModel 中的另一个 Ajax 调用...。

任何关于在单个视图中处理多个 ViewModel 的观点表示赞赏:)

【问题讨论】:

标签: mvvm knockout.js data-binding knockout-mapping-plugin


【解决方案1】:

Knockout 现在支持多个模型绑定。 ko.applyBindings() 方法采用一个可选参数 - 将激活绑定的元素及其后代。

例如:

ko.applyBindings(myViewModel, document.getElementById('someElementId'))

这将激活限制为 ID 为 someElementId 的元素及其后代。

更多详情请见documentation

【讨论】:

  • 如果你想使用 jQuery 选择器,你需要添加 [0] 来指定一个实际的 DOM 元素(而不是 jQuery 对象),如下所示:ko.applyBindings(myViewModel, $('#someElementId')[0])
  • 这应该是公认的答案。您仍然可以像当前接受的答案一样使用主对象,然后将各个视图模型绑定到页面上的相应元素。这将节省性能,并限制数据绑定所需的范围。
  • 是否可以用这种方法相互通信视图模型?即我有TaskVM和NoteVM。任务可以有备注。因此,我的 TaskVM 必须有一个 observableArray,即类型为 TaskVM 的笔记。你能分享一个这样的例子吗?
  • 最好在新问题中询问虚拟机之间的通信。
【解决方案2】:

如果它们都需要在同一个页面上,一种简单的方法是拥有一个包含其他视图模型的数组(或属性列表)的主视图模型。

masterVM = {
    vmA : new VmA(),
    vmB : new VmB(),
    vmC : new VmC(),
}

如果需要,您的masterVM 可以为页面本身具有其他属性。在这种情况下,视图模型之间的通信不会很困难,因为您可以通过 masterVM 进行中继,或者您可以在绑定中使用 $parent / $root 或其他一些自定义选项。

【讨论】:

  • 那么我是否能够执行类似的操作:data-bind="text: masterVM.vmA",我想我仍然可以使用 ko.applyBindings 并附加 DOM 元素。假设这也意味着我可以这样做:data-bind="$parent.masterVm"?
  • @CLiown 可以使用with:绑定,就不再赘述了
  • @CLiown 是的,如果您绑定到 masterVM,您可以这样做。当您深入到子视图模型时,您还可以使用“with”绑定来帮助避免点语法。
  • 我认为这种方法是一种非常严格的方法......现在我使用的是 ASP.Net MVC4,这无济于事,因为会有部分视图拥有自己的 ViewModels ,而部分/内容部分,不应该相互干扰,并且由于条件渲染,使用这种方法真的很难。
  • @bhuvin 使用 将帮助您处理多个视图模型和部分视图部分。请参阅knockmeout.net/2012/05/quick-tip-skip-binding.html 了解更多信息。
【解决方案3】:

这是我在完成非常大的项目(在单个视图中包含大量 ViewModel)后的回答。

HTML 视图

    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <div id="container1">
        <ul>
            <li >Container1 item</li>
            <!-- ko foreach: myItems -->
            <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <div id="container2">
        <ul>
            <li >Container2 item</li>
            <!-- ko foreach: myItems -->
                <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <script src="js/jquery-1.11.1.js"></script>
    <script src="js/knockout-3.0.0.js"></script>
    <script src="js/DataFunction.js"></script>
    <script src="js/Container1ViewModel.js"></script>
    <script src="js/Container2ViewModel.js"></script>

</body>
</html>

对于这个视图,我在两个单独的 javascript 文件中为 id=container1 和 id=container2 创建了 2 个视图模型。

Container1ViewModel.js

function Container1ViewModel()
{
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("ABC");
    self.myItems.push("CDE");

} 

Container2ViewModel.js

function Container2ViewModel() {
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("XYZ");
    self.myItems.push("PQR");

}

然后在这 2 个视图模型在 DataFunction.js 中注册为单独的视图模型之后

var container1VM;
var container2VM;

$(document).ready(function() {

    if ($.isEmptyObject(container1VM)) {
        container1VM = new Container1ViewModel();
        ko.applyBindings(container1VM, document.getElementById("container1"));
    }

    if ($.isEmptyObject(container2VM)) {
        container2VM = new Container2ViewModel();
        ko.applyBindings(container2VM, document.getElementById("container2"));
    }
});

像这样,您可以为单独的 div 添加任意数量的视图模型。但请确保不要为已注册 div 中的 div 创建单独的视图模型。

【讨论】:

  • 是否可以在其他视图模型中使用这种视图模型,而不是作为 DOM 的单独元素?
  • 这个解决方案为我赢得了奖杯。我正在开发一个复杂的 UI,需要生成无穷无尽的表单,这些表单可以根据用户输入的标准和一些基于收集的数据提供的上下文线索进行更改。所有其他解决方案都以某种方式限制了我。
【解决方案4】:

检查用于 Knockout JS 的 MultiModels 插件 - https://github.com/sergun/Knockout-MultiModels

【讨论】:

  • 这比 ko.applyBindings(viewModel, document.getElementById("divName")) 有什么优势?不就是语法糖吗?
  • @Paolo del Mundo 它还增加了对 LiveQuery 插件的依赖。
  • @PaolodelMundo 插件的目的是能够以 decalrative 方式使用视图模型集
【解决方案5】:

我们使用组件来实现这一点。 (http://knockoutjs.com/documentation/component-overview.html)

例如我们正在开发这个组件库:https://github.com/EDMdesigner/knobjs

如果您深入研究代码,您会看到例如我们在多个地方重用了旋钮按钮组件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 2020-01-14
    • 2016-09-19
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    相关资源
    最近更新 更多