我一直在尝试将ko viewmodel保存到浏览器历史记录中并将其返回到popstate事件中。目前没有抛出任何错误,但是在popstate上没有任何改变。我正在尝试的基本流程是这样的:
var storeViewModel = function (){
return ko.toJSON(viewModel);
};
function viewModel() {
var self = this;
self.records = ko.observableArray();
// add an object to the array and save view model
self.addRecord = function () {
self.records.push(new record());
// call the storeViewModel function push viewModel to history
history.pushState(storeViewModel(), "");
}
// set view model to stored view model object on forward / back navigation navigation
window.onpopstate = function (event) {
self = ko.utils.parseJson(event.state);
}
}
ko.applyBindings(new viewModel());
我已经多次阅读了mozilla文档。一切似乎都有意义,但我在实施方面遇到了麻烦。谢谢你的帮助!
答案 0 :(得分:1)
您不会保存视图模型,但它包含数据。
最方便的方法是使用自动映射。淘汰赛有mapping plugin;它允许您轻松地将原始数据转换为工作视图模型,并将工作视图模型转换回原始数据。
默认情况下,映射插件分别将原始数据的所有属性映射到observable
或observableArray
,但可以在映射定义中进行微调(参见文档)。
这基本上是这样的:
ko.mapping.fromJS(data, {/* mapping definition */}, self);
然后像这样:
ko.mapping.toJS(self);
我建议您设置所有的视图模型,以便他们可以从原始数据中自行引导:
function Record(data) {
var self = this;
// init
ko.mapping.fromJS(data, Record.mapping, self);
}
Record.mapping = {
// mapping definition for Record objects, kept separately as a constructor
// property to keep it out of the individual Record objects
};
和
function ViewModel(data) {
var self = this;
self.records = ko.observableArray();
self.init(data);
self.state = ko.pureComputed(function () {
return ko.mapping.toJS(self);
});
}
ViewModel.mapping = {
// mapping rules for ViewModel objects
records: {
create: function (options) {
return new Record(options.data);
}
}
};
ViewModel.prototype.init = function (data) {
// extend a default data layout with the actual data
data = ko.utils.extend({
records: []
}, data);
ko.mapping.fromJS(data, ViewModel.mapping, this);
};
ViewModel.prototype.addRecord = function () {
this.records.push(new Record());
};
映射插件会跟踪它在.fromJS
步骤中映射的所有属性,并仅返回.toJS()
步骤中的属性。任何其他属性(如计算机)都将被忽略。
这也是ko.utils.extend
- 建立您希望映射插件处理的基线属性集的原因。
由于淘汰赛的内置依赖关系跟踪,每次状态相关数据发生变化时,state
计算值都会发生变化。
现在剩下的就是处理页面加载事件:
// initialize the viewmodel
var vm = new ViewModel(/* possible init data from elsewhere */);
// subscribe to VM state changes (except for changes due to popState)
var popStateActive = false;
vm.state.subscribe(function (data) {
if (popStateActive) return;
history.pushState(ko.toJSON(data), "");
});
// subscribe to window state changes
ko.utils.registerEventHandler(window, "popstate", function (event) {
popStateActive = true;
vm.init( ko.utils.parseJson(event.state) );
popStateActive = false;
});
// and run it
ko.applyBindings(vm);