使用 ViewModel 构造函数淘汰虚拟组合

Posted

技术标签:

【中文标题】使用 ViewModel 构造函数淘汰虚拟组合【英文标题】:Knockout virtual compose with ViewModel constructors 【发布时间】:2013-04-05 08:39:58 【问题描述】:

我在使用 3 对 Views/ViewModels 进行虚拟 Knockout 组合时遇到了一些奇怪的功能

autoAttendant.js

define(['durandal/app', 'viewmodels/settings/autoAttendant/menu'], function(app, Menu)

    return function() 
        var self = this;

        self.attendant = ko.observable();

        self.activate = function() 
            self.autoAttendant(new Menu());
        ;
    ;
);

autoAttendant.html

<div id="content_pane" class="pushed_right">
    <div class="content_box">
        <h1>Attendant</h1>

        <!-- ko compose: 'viewmodels/settings/autoAttendant/menu' --><!--/ko-->

    </div>
</div>

menu.js

define(['durandal/app', 'viewmodels/settings/autoAttendant/menuItem'], function(app, MenuItem) 

    return function() 
        var self = this;

        self.menuItems = ko.observableArray([
            new MenuItem('val1', 'label1'),
            new MenuItem('val2', 'label2'),
            // etc...
        ]);
    ;
);

menu.html

<div class="list">
    <div class="box_item master">
        <!-- html content -->
    </div>
    <!-- ko foreach:  data: menuItems  -->
        <!-- ko compose: 'viewmodels/settings/autoAttendant/menuItem' --><!--/ko-->
    <!-- /ko -->
</div>

menuItem.js

define(['durandal/app'], function(app) 
    var menuItem =  function(val, label, active) 
        var self = this;

        console.log('val:', val, 'label:', label, 'active:', active); // purely for testing purposes

        var _val = val || 'default_val',
            _label = label || 'default_label',
            _active = active || false;

        self.val = ko.observable(_val);
        self.label = ko.observable(_label);
        self.active = ko.observable(_active);
    ;
    return menuItem;
);

menuItem.html

<div class="level">
    <div class="box_item clickable">
        <!-- html content -->
    </div>
</div>

这些共同代表设置中的单个页面,该页面显示菜单和该菜单的子项。

Menu 和 MenuItem 必须从伴随的 View/ViewModel 中分离出来,因为菜单本身是递归的,并且 menuItem 可以链接到具有自己的 menuItems 的子菜单。

问题出现在第二个ko composeconsole.log 出现 3 次,前 2 次显示正确传递给 menu.js 中的 MenuItem 构造函数的参数:

val: val1 label: label1 active: undefined

在最后的console.log打印输出时,已经传递的参数被覆盖如下:

val: <!-- ko compose: 'viewmodels/settings/autoAttendant/menuItem' --><!--/ko--> label: Object model: "viewmodels/settings/autoAttendant/menuItem", bindingContext: L.b.z, activeView: null active: undefined

为什么会这样?

【问题讨论】:

您是否尝试在运行 foreach 循环之前检查您的 menuItems?类似的东西&lt;span data-bind="text: ko.toJSON($data.menuItems)"&gt;&lt;/span&gt;&lt;!-- ko foreach: data: menuItems --&gt; 下一个想法:如果 menuItems 本身没有问题,这里是 Durandal 源代码中的 ko.compose。 github.com/BlueSpire/Durandal/blob/master/App/durandal/… 在github.com/BlueSpire/Durandal/blob/master/App/durandal/… 周围设置断点应该有助于澄清事情。 我在ko foreach 前后放置了带有menuItems toJSON 的span,并且menuItems 的格式正确。因此,当切换到组合的 menuItem 上下文时,这些值会丢失或被覆盖。 【参考方案1】:

在对源代码进行深入研究和(不止)一点实验之后,以下方法奏效了:

&lt;!-- ko compose: view:'settings/autoAttendant/menuItem' --&gt;&lt;!--/ko--&gt;

来自Durandal docs on compose

【讨论】:

现在你发现它是有道理的。已经有 ko.observable menuItems 包含所有 new MenuItem(...),因此定义视图就是所需要的。不知道杜兰达尔这么聪明,谢谢分享。

以上是关于使用 ViewModel 构造函数淘汰虚拟组合的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Xamarin 和 Autofac 将构造函数依赖项注入 ViewModel?

如何使用 Xamarin.Forms.DependencyService 注入具有构造函数注入的 ViewModel

在 viewmodel 的构造函数中调用异步方法加载数据有警告

如何使用带有两个构造函数的viewmodel的Unity框架显示子窗口?

[Catel]如何将带有构造函数参数的 ViewModel 传递给 TabService 扩展方法?

从 ViewModel 构造函数 Xamarin.Forms 调用异步方法