继承DurandalJS中的常用函数

时间:2013-10-11 12:53:24

标签: javascript inheritance prototype durandal

我正在寻找一种更好的方法来处理我的DurandalJS应用程序中的继承,从baseViewModel.js到其他页面。这是我目前的应用结构:

  • baseViewModel.js
  • 主壳
    • 组1 shell
      • 第1页
      • 第2页
    • 组2 shell
      • 第1页
      • 第2页

所有这些页面共享一些常用功能(baseViewModel.js),例如:

  • isLoading:一个可观察的内容,用于检查网页上是否有内容正在加载
  • isValid:检查表单是否有效
  • afterAdd和beforeRemove对添加和删除项目的影响
  • 表单的键盘快捷键
  • 模板切换功能

目前如何运作

  1. baseViewModel.js内的所有内容都声明为self.*,其中self是对Window对象的引用,例如:

    self.showElement = function(elem) {
      if (elem.nodeType === 1) $(elem).hide().fadeIn();
    }
    
    self.fadeRemove = function(elem) {
      if (elem.nodeType === 1) $(elem).fadeOut(500, function() { $(elem).remove(); });
    }
    
  2. 我在主shell中只定义了baseViewModel.js 一次,然后在整个应用中访问它,如下所示:

    <tbody data-bind="foreach: { data: dataArr, afterAdd: showElement, beforeRemove: fadeRemove }">
    

    或在视图模型中:

    Page1.load = function() {
      self.isLoading(true);
      // get data
    };
    
  3. 我尝试了什么

    我研究了原型继承并设法让它工作,但我不确定我实现它的方式。我在Base中创建了一个baseViewModel.js函数,并将其作为单例返回。然后在其中一个页面中,我做了:

    define(['durandal/app', 'jquery', 'knockout', 'baseViewModel'], function (app, $, ko, base) {
    
      var Page1 = function() {};
    
      Page1.prototype = base;
    
      return Page1;
    
    });
    

    Base中声明的函数在Page1的视图和视图模型中工作得很好,但问题是我需要它们在与Page1一起加载的所有模块中工作。这包括:

    • 组1 shell视图(有一个激活Base内部功能的按钮)
    • 主shell视图(加载栏基于Base中isLoading可观察值的值可见)

    为了使这些工作正常,我必须定义文件并在每个视图模型中应用相同的*.prototype = base;

    那么有更好的方法来处理继承吗?如果没有,有没有办法只声明一次基础并将其应用于所有子页面?

    谢谢!

2 个答案:

答案 0 :(得分:3)

我将原型继承与工厂方法结合使用,到目前为止似乎运行良好。我只想要简单的继承,所以这不是像一些继承库那样的全功能继承方法。

正如PW建议的那样,我的基本视图模型包含在requireJs模块中。

这是一个简化的代码示例,但它应该是有用的。让我知道它是否有意义,我可以详细说明。

基本视图模型

define(function (require) {
    "use strict";

    function ViewModelBase() {

        //this is the activate function that Durandal will call
        function activate() {

            //call activate on derived vm
            if (this.onActivate) {
                return this.onActivate.apply(this, arguments);
            } else {
                return true;
            }
        }

        //validate view model and display all remaining errors
        function validate() {
            // passing 'this' so that the viewmodel instance is evaluated at the time it's needed 
            return validation.validateViewModel(this);   //this is knockout validation
        }

        //exports
        this.activate = activate;
        this.validate = validate;
    };

    //return the constructor (non-singleton)
    return ViewModelBase;
});

<强>工厂

define(function (require) {
    "use strict";

    return {
        createViewModel: function (ctor) {
            ctor.prototype = new (require("view-model-base"))();
            ctor.prototype.constructor = ctor;
            return ctor;
        }
    };

});

派生的视图模型

define(function (require) {
    "use strict";

    var factory = require("fusion/factory");
    var HomeViewModel = factory.createViewModel(function () {
        var __viewModel = this; //use __viewModel variable to access this view model instance.

        function onActivate() {
            //add application startup logic here

            //access public functions on the base view model like this:
            __viewModel.validate();

            return true;
        }
        this.onActivate = onActivate;
    });

    //returns the constructor (non-singleton)
    return HomeViewModel;

    //to return a singleton instead, do this
    return new HomeViewModel();


}); // END :: define statement

答案 1 :(得分:0)

mixins 是可以考虑在模块之间共享功能的另一种模式。 请注意 @Joseph Gabriel答案肯定是正确答案。对于某些用例,Mixins只是一个较轻的替代品,但它们不提供任何类型的继承。

编辑示例和实时版本已更新,以便更好地展示需要放置的位置,以便成为a)常见的b)共享c)在所有Page个实例中唯一。< / p>

common.js

/*globals define */
define(['jquery', 'knockout'], function($, ko) {
    "use strict";

    // common must return a singleton
    return {
        commonObservable: ko.observable('commonObservable: Defined in common.js.  Click me...'),
        showElement: function( model, elem ) {
            var target = elem.currentTarget;
            if ( target.nodeType === 1 ) {
                $(target).hide().fadeIn();
            }
        },
        fadeRemove: function( model, elem ) {
            var target = elem.currentTarget;
            if ( target.nodeType === 1 ) {
                $(target).fadeOut(500, function() {
                    $(target).remove();
                });
            }
        }
    };
});

页面视图模型

/*globals define */
define(['durandal/app', 'jquery', 'knockout', './common'], function( app, $, ko, common ) {
    "use strict";
    var Page = function() {
        this.uniqueObservable = ko.observable('uniqueObservable: Page property. Click me... ');
    };

    // Extend the prototype with the common properties and
    // `extend` it further with shared properties
    $.extend(true, Page.prototype, common, {
         sharedObservable : ko.observable('sharedObservable: mixed in after common. Click me...')
    });


    return Page;

});

页面视图

<div>
    <h1>mixin sample</h1>

    <ul class="unstyled ">
        <li data-bind="text: commonObservable, click: fadeRemove"></li>
        <li data-bind="text: sharedObservable, click: fadeRemove"></li>
        <li data-bind="text: uniqueObservable, click: fadeRemove"></li>
    </ul>    
</div>

实时版本位于:http://dfiddle.github.io/dFiddle-2.0/#extras/mixin