【问题标题】:Inheritance for durandal (HotTowel) viewmodels?durandal(HotTowel)视图模型的继承?
【发布时间】:2013-08-22 05:28:35
【问题描述】:

简单的问题,很确定这是一个复杂的答案:)

是否可以在 Durandal 中为视图模型实现某种形式的继承?

所以如果你有一个类似这样的视图模型:

define(['durandal/app', 'services/datacontext', 'durandal/plugins/router', 'services/logger'],
    function (app, datacontext, router, logger) {
        var someVariable = ko.observable();
        var isSaving = ko.observable(false);

        var vm = {
            activate: activate,
            someVariable : someVariable,
            refresh: refresh,
            cancel: function () { router.navigateBack(); },
            hasChanges: ko.computed(function () { return datacontext.hasChanges(); }),
            canSave: ko.computed(function () { return datacontext.hasChanges() && !isSaving(); }),
            goBack: function () { router.navigateBack(); },
            save: function() {
                isSaving(true);
                return datacontext.saveChanges().fin(function () { isSaving(false); })
            },
            canDeactivate: function() {
                if (datacontext.hasChanges()) {
                    var msg = 'Do you want to leave and cancel?';
                    return app.showMessage(msg, 'Navigate Away', ['Yes', 'No'])
                        .then(function(selectedOption) {
                            if (selectedOption === 'Yes') {
                                datacontext.cancelChanges();
                            }
                            return selectedOption;
                        });
                }
                return true;
            }
        };

        return vm;

        //#region Internal Methods
        function activate(routeData) {
            logger.log('View Activated for id {' + routeData.id + '}, null, 'View', true);
            });
        }
        //#endregion

        function refresh(id) {
            return datacontext.getById(client, id);
        }
    });

是否有可能将其制成某种基本类型并从中继承更多视图模型,能够扩展需求列表等等?

对此还有另一个问题,但视图模型似乎与我为 durandal/HotTowel 构建的视图模型不太一样。

谢谢。

【问题讨论】:

    标签: durandal hottowel


    【解决方案1】:

    我很确定这可以通过 jQuery 的扩展方法来完成。这是我刚刚想到的,所以我可能遗漏了一些东西,但一个基本的例子可能是这样的:

    basevm.js

    ... your mentioned viewmodel
    

    继承vm.js

    define(['basevm'], function (basevm) {
       var someNewObservable = ko.observable();
    
       var vm = $.extend({
            someNewObservable : someNewObservable
       }, basevm);
    
       return vm;
    });
    

    请让我知道这是否有效。我只是从头顶编码,尚未经过测试。

    【讨论】:

    • 嗨,对不起,我花了这么长时间才回来。这看起来确实很有效,但这是否意味着基本上每个使用这种技术的视图模型都将共享一个 basevm?我对 durandal 的理解是,像这样注入的模型会有一个单例的生命周期?不过我可能还差得很远。谢谢!
    • 据我所知,这将有一个单身人士的生命周期,是的。
    • 这是迄今为止最简单的方法。根据您对基本视图模型所做的操作,单例生命周期是可以接受的。就我而言,我主要将它用于公共代码,而不是可能与单例生命周期混淆的公共属性。
    【解决方案2】:

    只是根据你的说法,我想出了这个。让我知道这是否适合您,如果不适合,请告诉我我做错了什么。

    谢谢。

    viewmodelBase

    define(['durandal/app', 'services/datacontext', 'durandal/plugins/router', 'services/logger'],
        function (app, datacontext, router, logger) {
            var vm = function () {
                var self = this;
                this.someVariable = ko.observable();
                this.isSaving = ko.observable(false);
                this.hasChanges = ko.computed(function () { return datacontext.hasChanges(); });
                this.canSave = ko.computed(function () { return datacontext.hasChanges() && !self.isSaving(); });
            };
    
            vm.prototype = {
                activate: function (routeData) {
                    logger.log('View Activated for id {' + this.routeData.id + '}', null, 'View', true);
                },
                refresh: function (id) {
                    return datacontext.getById(client, id);
                },
                cancel: function () {
                    router.navigateBack();
                },
                goBack: function () { router.navigateBack(); },
                save: function() {
                    var self = this;
                    this.isSaving(true);
                    return datacontext.saveChanges().fin(function () { self.isSaving(false); })
                },
                canDeactivate: function() {
                    if (datacontext.hasChanges()) {
                        var msg = 'Do you want to leave and cancel?';
                        return app.showMessage(msg, 'Navigate Away', ['Yes', 'No'])
                            .then(function(selectedOption) {
                                if (selectedOption === 'Yes') {
                                    datacontext.cancelChanges();
                                }
                                return selectedOption;
                            });
                    }
                    return true;
                }
            };
    
            return vm;
        });
    

    父视图模型

    define([viewmodelBase], function (vmbase) {
        var vm1 = new vmbase();
        vm1.newProperty = "blah";
        var vm2 = new vmbase();
    });
    

    【讨论】:

    • 嗨,埃文。抱歉,我已经很久没有回过头来了。问题;在您的方法中,您可以扩展注入的服务吗?因此,在您的基础中,您有应用程序、数据上下文等,而在子 [viewModelBase] 中。你可以简单地用 ([viewModelBase], 'services/service1', 'services/service2', function (vmbase, service1, serivce2) 扩展它吗?
    • 使用 javascript 有各种类型的关于如何进行继承的模式。他们都有自己的好处,有些比其他的更复杂。我只想谷歌 javascript 原型继承并找到适合您的场景的解决方案。
    【解决方案3】:

    我在博客上写了一篇文章来解决这个问题。简而言之,我在我的一个项目中为我的所有模式对话框视图使用原型继承。这是我写的帖子的link(请随意跳到代码部分)和一个演示它的jsFiddle example

    可以在 Durandal 中工作的简化示例(注意:每个视图模型都返回其构造函数,而不是对象):

    viewmodels/modal.js

    define(['durandal/system'], 
    function(system) { 
      var modal = function () {
        this.name = 'Modal';
      }
    
      modal.prototype = {
        activate: function() {
            system.log(this.name + ' activating');
        },
        attached: function(view) {
            system.log(this.name + ' attached');
        },
        deactivate: function() {
            system.log(this.name + ' deactivating');
        },
        detached: function(view, parent) {
            system.log(this.name + ' detached');
        }
      };
    
      return modal;
    });
    

    viewmodels/child.js

    define(['durandal/system', 'viewmodels/modal'],
    function(system, Modal) {
      var child = function() {
        this.name = 'Child Modal';
      }
    
      // inherits from Modal
      child.prototype = new Modal();
      child.prototype.constructor = child;
      child.prototype._super = Modal.prototype;
    
      // overrides Modal's activate() method
      child.prototype.activate = function() {
        this._super.activate.call(this);  // we can still call it from the _super property
        system.log(this.name + ' activating [overridden version]');
      };
    
      return child;
    });
    

    我更喜欢这个实现,因为它支持代码重用,在 javascript 允许的情况下尽可能符合 OOP 原则,并且它使我能够在需要时通过 _super 属性调用基类的方法。您可以根据需要轻松转换。

    【讨论】:

      猜你喜欢
      • 2013-05-30
      • 1970-01-01
      • 2013-03-12
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 2019-01-27
      • 2014-11-03
      • 1970-01-01
      相关资源
      最近更新 更多