Javascript 继承DurandalJS中的公共函数

Javascript 继承DurandalJS中的公共函数,javascript,inheritance,prototype,durandal,Javascript,Inheritance,Prototype,Durandal,我正在寻找一种更好的方法来处理DurandalJS应用程序中的继承,从baseViewModel.js到其他页面。以下是我当前的应用程序结构: baseViewModel.js 主壳体 第一组外壳 第1页 第2页 第2组外壳 第1页 第2页 所有这些页面都共享一些通用功能(baseViewModel.js),例如: isLoading:检查页面上是否加载了内容的可观察对象 isValid:检查表单是否有效 添加和删除项目的afterAdd和beforeRemove效果 表单的键

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

  • baseViewModel.js
  • 主壳体
    • 第一组外壳
      • 第1页
      • 第2页
    • 第2组外壳
      • 第1页
      • 第2页
所有这些页面都共享一些通用功能(baseViewModel.js),例如:

  • isLoading:检查页面上是否加载了内容的可观察对象
  • isValid:检查表单是否有效
  • 添加和删除项目的afterAdd和beforeRemove效果
  • 表单的键盘快捷键
  • 模板切换功能
目前它是如何工作的
  • baseViewModel.js
    中的所有内容都声明为
    self.
    ,self是对窗口对象的引用,例如:

    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(); });
    }
    
  • 我在主shell中定义
    baseViewModel.js
    一次,然后通过应用程序访问它,如下所示:

    <tbody data-bind="foreach: { data: dataArr, afterAdd: showElement, beforeRemove: fadeRemove }">
    
  • 我试过的 我研究了原型继承并设法使其工作,但我不确定我实现它的方式。我在
    baseViewModel.js
    中创建了一个
    Base
    函数,并将其作为单例返回。然后在其中一页中,我做了:

    define(['durandal/app', 'jquery', 'knockout', 'baseViewModel'], function (app, $, ko, base) {
    
      var Page1 = function() {};
    
      Page1.prototype = base;
    
      return Page1;
    
    });
    
    在Base中声明的函数在Page1的视图和视图模型中工作得很好,但问题是我需要它们在与Page1一起加载的所有模块中工作。这包括:

    • 第1组外壳视图(在基座内有一个按钮可激活功能)
    • 主壳体视图(根据底座内部可观察到的
      isLoading
      值,加载条可见)
    为了使这些工作正常,我必须定义文件并应用相同的
    *。prototype=base在每个视图模型中

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


    谢谢

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

    正如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";
    
        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
    
    工厂

    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";
    
        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";
    
        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
    

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

    编辑已更新示例和实时版本,以更好地展示需要放置的位置,以便a)公共b)共享c)在所有
    页面
    实例中唯一

    common.js 页面视图模型 页面视图
    
    混合样品
    

    现场版可在以下网址获得:

    似乎原型设计是一种方法。您是否考虑过在require.js的配置中注册base,以便它可以始终与诸如baseVM.whatever()之类的常用词一起使用?我不知道它是否能帮你找到你想要的东西,所以就把它作为评论扔进去。你看过打字稿了吗?它使JavaScription中的继承变得很容易,谢谢您的回答。我注意到,在视图模型中声明Page1之后,如果我只使用
    Page1.prototype=new(require(“视图模型库”)()
    Page1.prototype.constructor=Page1
    ,我似乎会得到相同的结果。我遗漏了什么区别吗?不,我想是一样的。我正在为一个企业开发一个框架,工厂为我提供了另一个抽象层,以防我以后需要更改技术或添加功能
    /*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>