4

我在这里有一个测试用例:http: //tremby.net/knockouttest/page1.php

我正在使用 pjax 进行页面转换。在上面的测试用例的第 1 页和第 2 页之间单击会异步加载两个页面,然后替换元素的内容#main。在此过程中会推送浏览器历史状态,因此位置栏中的 URL 会更新,并且后退按钮应该让我们回到原来的位置。

第 1 页上的列表填充了敲除的foreach绑定和List我定义的模型(在头部的内联脚本中)。在ready第 1 页上,内联脚本运行ko.applyBindings,因此列表被填充。

“添加项目”按钮将项目添加到视图模型,然后将其剔除添加到列表中。

添加一些项目,然后转到第 2 页,然后返回第 1 页,列表是新的,最初有 3 个项目,添加项目按钮仍然有效。这对我们的用例来说很好。

添加一些项目然后转到第 2 页,然后使用浏览器的后退按钮返回第 1 页,另一方面,这就是我的问题所在。新项目仍然可见(这很好,并且在使用浏览器的后退按钮时对我们的用例至关重要),但“添加项目”按钮现在已损坏。将新项目推送到的代码observableArray肯定正在运行,但似乎绑定已经消失,因此淘汰赛不知道添加新的 DOM 元素。

我无法在 上ko.applyBindings再次运行该功能popstate,否则淘汰赛现在会认为我希望为列表中的每个项目复制每个现在存在的项目,然后每次单击“添加项目”都会给出多个新项目。

我有一种强烈的感觉,我缺少一些明显的东西,但我找不到任何看起来对文档有帮助的东西。任何帮助将非常感激。

4

1 回答 1

1

您看到这种行为是因为尽管已将视图模型绑定到 UI,但您并没有将其持久化到浏览器历史可以访问它的任何地方,以便在您期望的状态下重建页面。使用浏览器的内置按钮backforward按钮也可以观察到这种行为。我在解决这个问题时选择采用的通常模式如下;

首先,分配给this一个变量,这将在以后为您省去麻烦。视图模型现在应该看起来像这样;

function List(items) {
    var self = this;
    self.items = ko.observableArray(items)
    self.addItem = function(text) {
        self.items.push(text)
    }
}

现在创建一个计算的 observable 序列化你的视图模型的当前状态。这完全取决于您选择如何实施它。

self.toJson = ko.computed(function(){
    /*** Serialise self.items() and return the string ***/
    return myJsonString;
});

接下来,将计算结果绑定到隐藏的输入,这将确保视图模型在表单数据中持久化,从而允许您稍后重新水化视图模型。

<input id="serialisedItems" type="hidden" data-bind="value: toJson" value="[1,4,3]" />

最后,以这种方式重新水化视图模型$.ready()

$(function() {
    var items = $('#serialisedItems').val();
    /*** Deserialise items before passing into the List ***/
    var list = new List(deserialisedItems);
    ko.applyBindings(list);
});

在这一点上我还应该指出,该列表已通过设置 的 value 属性进行初始化<input>

于 2013-11-12T09:39:30.370 回答