假设我有以下 durandal 代码:
define(['durandal/app', 'plugins/http'], function (app) {
var vm = function(){
var self = this;
self.myData = ko.observableArray([]);
}
};
vm.activate = function() {
this.myData([]);
};
vm.deactivate = function(){
};
return vm;
};
我知道通过返回构造函数,每次激活 View 模型时,它都会 返回一个新实例。
我的问题是:无论如何,当我访问时,如果之前访问中有 myData()
,那么我不想设置 this.myData([]);
但要使用之前的 myData()
?
我知道通过返回一个单例对象可以做到这一点,但是如果我想保留构造函数,我可以这样做吗?
另一个问题,如果您要获取新实例,从而保证“干净”的对象,那么在上面的代码中激活和停用有什么意义?
最佳答案
您可以采取多种方法,我在下面列举了这些方法。
对于下面的所有示例,请考虑选择“项目”主题。
注入(inject)(无 View )
通过这种方法,我们将 ProjectsServices 模块(单例)注入(inject)到 Projects 模块(实例)中。但只有当 ProjectsServices 不提供一个或多个 View 时,这种方法才有效。下面,我将向您展示如果我们的服务模块本身也提供一个或多个 View ,我们可以做什么。
ProjectsServices ViewModel(单例) servicesProjects.js
define('projectsServices', [],
function() {
var myData = null; //this may or may not be an observable
return {
myData: myData //we return an object literal, which is what makes this module a singleton
};
}
);
项目 ViewModel(实例) projects.js
define('projects', ['projectsServices'],
function(services) {
//Constructor
var Projects = function () {
this.myData = ko.observable(); //this may or may not be an observable
};
Projects.prototype.activate = function (activationData) {
this.myData(services.myData);
};
Projects.prototype.detached = function () {
services.myData = this.myData(); /store back to the services module for later use
};
return Projects; //we return a constructor function, which is what makes this module an instance
}
);
主机-客户端(查看)
通过这种方法,Projects 模块由 ProjectsServices 模块内部组成,并且我们通过 activationData
上的可观察对象来回传递 myData
。此外,这种方法假设服务模块不仅提供代码服务,还提供 View 服务。弹出在其他表单之上的全局“添加联系人”表单是基于 View 的服务模块的示例。当然,“添加联系人” View 后面会有一个 viewModel,它代表用于添加联系人的代码服务。
ProjectsServices ViewModel(单例) servicesProjects.js
define('projectsServices', [],
function() {
var myData = ko.observable(); //should be an observable
}
);
项目服务 View servicesProjects.html
/*We bring in the Projects module through composition and pass in the observable, `myData`, itself (not `myData()`, but `myData`)*/
<div>
<div data-bind="compose: {model: 'viewmodels/projects', activationData: myData}">
</div>
</div>
项目 ViewModel(实例) projects.js
define('projects', [],
function() {
//Constructor
var Projects = function () {
this.myDataLocal = ko.observable(); //this may or may not be an observable
this.myDataFromServices = null;
};
Projects.prototype.activate = function (activationData) {
this.myDataFromServices = activationData
this.myDataLocal(activationData());
};
Projects.prototype.detached = function () {
this.myDataFromServices(this.myDataLocal()); /store back to the services module for later use
};
return Projects; //we return a constructor function, which is what makes this module an instance
}
);
项目 View projects.html
/*There are infinite number of ways to bind to your myDataLocal*/
<div>
<div data-bind="text: myDataLocal}">
</div>
</div>
发布-订阅
通过这种方法,我们通过 app
利用 Durandal 的内置发布/订阅功能。这种方法可以与上面给出的注入(inject)或主机客户端一起使用。该策略是从实例模块的 activate
处理程序发布请求消息,并在同一处理程序内接收回复消息,这两个消息的目的是请求和提供 myData
(大概是之前保存的)。当我们准备好将 myData
保存回服务模块时,我们会发送另一条以 myData
作为负载的消息。
ProjectsServices ViewModel(单例) servicesProjects.js
define('projectsServices', ['durandal/app'],
function(app) {
var
myData = null, //this may or may not be an observable
activate = function () {
app.on('requestForMyData').then( function () {
app.trigger('responseMyData', myData);
});
app.on('storeMyData').then( function (data) {
myData = data; //where 'data' is the payload
});
},
detached = function () {
app.off('requestForMyData');
app.off('storeMyData');
};
return {
myData: myData, //we return an object literal, which is what makes this module a singleton
activate: activate,
detached: detached
};
}
);
项目 ViewModel(实例) projects.js
define('projects', ['durandal/app'],
function(app) {
//Constructor
var Projects = function () {
this.myData = ko.observable(); //this may or may not be an observable
};
Projects.prototype.activate = function () {
var that = this;
app.on('responseMyData').then( function (data) {
that.myData(data);
});
app.trigger('requestForMyData'); //no payload
};
Projects.prototype.detached = function () {
app.trigger('storeMyData', this.myData());
app.off('responseMyData');
};
return Projects; //we return a constructor function, which is what makes this module an instance
}
);
在这种情况下, View 不会改变,因此此处未提供它们。
消息总线
这种方法实际上与发布-订阅方法相同,只是我们使用的是客户端消息总线,例如 postal.js。正如您将看到的,它更加精致。这也恰好是我们在生产中采用的方法。这种方法应该与上面的主机-客户端方法一起使用,只是我们只是传递消息 channel ,而不是数据本身。
- 您可以下载postal.js here .
- 查看我 (@estaylorco) 在 Github 上与 Jim Cowart (@ifandelse) 的交流 here , here ,和 here .
- 查看 RC postal.request-response (我在下面不使用它,因为它是预览版),以及我在那里的交流。 postal.request-response 是我要求的(双向 channel ),它仅适用于您正在使用的场景。它极大地简化了请求-响应场景。
ProjectsServices ViewModel(单例) servicesProjects.js
define('projectsServices', ['postal'],
function(postal) {
var
outletMessageChannel = 'someuniqueidentifier',
subscriptions = [],
myData = null, //this may or may not be an observable
activate = function () {
var that = this;
subscriptions.push(postal.subscribe({
channel: outletMessageChannel,
topic: 'request.mydata',
callback: function () {
postal.publish({
channel: outletMessageChannel,
topic: 'response.mydata',
data: that.myData
});
}
}));
subscriptions.push(postal.subscribe({
channel: outletMessageChannel,
topic: 'store.mydata',
callback: function (data) {
that.myData = data;
}
}));
},
detached = function () {
//I'm using underscore.js here, but you can use any approach to iterate over subscriptions
_.each(subscriptions, function(sub) {
sub.unsubscribe();
sub.callback = null;
sub = null;
});
subscriptions = null;
};
return {
myData: myData, //we return an object literal, which is what makes this module a singleton
activate: activate,
detached: detached
};
}
);
项目服务 View servicesProjects.html
/*We bring in the Projects module through composition and pass in the message channel*/
<div>
<div data-bind="compose: {model: 'viewmodels/projects', activationData: outletMessageChannel}">
</div>
</div>
项目 ViewModel(实例) projects.js
define('projects', ['postal'],
function(postal) {
//Constructor
var Projects = function () {
this.subscriptions = [];
this.outletMessageChannel = '';
this.myData = ko.observable(); //this may or may not be an observable
};
Projects.prototype.activate = function (activationData) {
this.outletMessageChannel = activationData;
var that = this;
subscriptions.push(postal.subscribe({
channel: this.outletMessageChannel,
topic: 'response.mydata',
callback: function (data) {
that.myData(data);
}
}));
postal.publish({
channel: this.outletMessageChannel,
topic: 'request.mydata',
data: null //no payload
});
};
Projects.prototype.detached = function () {
postal.publish({
channel: this.outletMessageChannel,
topic: 'store.mydata',
data: this.myData()
});
//I'm using underscore.js here, but you can use any approach to iterate over subscriptions
_.each(this.subscriptions, function(sub) {
sub.unsubscribe();
sub.callback = null;
sub = null;
});
this.subscriptions = null;
};
return Projects; //we return a constructor function, which is what makes this module an instance
}
);
请注意,在这种情况下,“项目” View 不会更改,因此此处不包含它。
关于javascript - Durandal构造函数但仍想记住数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23573100/