在pushstate / popstate上返回挖空视图模型

时间:2015-07-25 17:08:51

标签: javascript html5 dom knockout.js

我一直在尝试将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文档。一切似乎都有意义,但我在实施方面遇到了麻烦。谢谢你的帮助!

1 个答案:

答案 0 :(得分:1)

您不会保存视图模型,但它包含数据

最方便的方法是使用自动映射。淘汰赛有mapping plugin;它允许您轻松地将原始数据转换为工作视图模型,并将工作视图模型转换回原始数据。

默认情况下,映射插件分别将原始数据的所有属性映射到observableobservableArray,但可以在映射定义中进行微调(参见文档)。

这基本上是这样的:

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

在此处查看:http://jsfiddle.net/Tomalak/46c505gs/1/