我正在寻找一种更好的方法来处理我的DurandalJS应用程序中的继承,从baseViewModel.js
到其他页面。这是我目前的应用结构:
所有这些页面共享一些常用功能(baseViewModel.js),例如:
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(); });
}
我在主shell中只定义了baseViewModel.js
一次,然后在整个应用中访问它,如下所示:
<tbody data-bind="foreach: { data: dataArr, afterAdd: showElement, beforeRemove: fadeRemove }">
或在视图模型中:
Page1.load = function() {
self.isLoading(true);
// get data
};
我研究了原型继承并设法让它工作,但我不确定我实现它的方式。我在Base
中创建了一个baseViewModel.js
函数,并将其作为单例返回。然后在其中一个页面中,我做了:
define(['durandal/app', 'jquery', 'knockout', 'baseViewModel'], function (app, $, ko, base) {
var Page1 = function() {};
Page1.prototype = base;
return Page1;
});
Base中声明的函数在Page1的视图和视图模型中工作得很好,但问题是我需要它们在与Page1一起加载的所有模块中工作。这包括:
isLoading
可观察值的值可见)为了使这些工作正常,我必须定义文件并在每个视图模型中应用相同的*.prototype = base;
。
那么有更好的方法来处理继承吗?如果没有,有没有办法只声明一次基础并将其应用于所有子页面?
谢谢!
答案 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>
/*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>