我这里有一个测试用例:http://tremby.net/knockouttest/page1.php
我正在使用 pjax 进行页面转换。在上面的测试用例的第 1 页和第 2 页之间单击会异步加载两个页面,然后替换 #main
的内容元素。在此过程中会推送浏览器历史状态,因此位置栏中的 URL 会更新,并且后退按钮应该让我们回到原来的位置。
第 1 页的列表填充了 knockout 的 foreach
绑定(bind)和List
我定义的模型(在头部的内联脚本中)。在 ready
在第 1 页,内联脚本运行 ko.applyBindings
这样列表就被填充了。
“添加项目”按钮将项目添加到 View 模型,然后将其 knockout 添加到列表中。
添加一些项目,然后转到第 2 页,然后返回第 1 页,列表是新的,最初有 3 个项目,添加项目按钮仍然有效。这对我们的用例来说很好。
添加一些项目,然后转到第 2 页,但另一方面,使用浏览器的后退按钮返回第 1 页,这就是我的问题所在。新项目仍然可见(这很好,并且
当使用浏览器的后退按钮时,这对我们的用例至关重要),但“添加项目”按钮现在已损坏。将新项目推送到 observableArray
的代码肯定正在运行,但似乎绑定(bind)已经消失,因此 knockout 不知道添加新的 DOM 元素。
我无法运行 ko.applyBindings
在 popstate
上再次运行,或者 knockout 现在会认为我希望为列表中的每个项目复制每个现有项目,然后每次单击“添加项目”都会给出多个新项目。
我有一种强烈的感觉,我缺少一些明显的东西,但我找不到任何看起来对文档有帮助的东西。任何帮助将非常感激。
最佳答案
您看到这种行为是因为尽管已将 View 模型绑定(bind)到 UI,但您并没有将其持久化到浏览器历史可以访问它的任何地方,以便在您期望的状态下重建页面。使用浏览器的内置 back
也可以观察到这种行为。和 forward
纽扣。我在解决这个问题时选择采用的通常模式如下;
首先,分配this
到一个变量中,这将为您节省 hassle later on . View 模型现在应该看起来像这样;
function List(items) {
var self = this;
self.items = ko.observableArray(items)
self.addItem = function(text) {
self.items.push(text)
}
}
现在创建一个计算的 observable 序列化你的 View 模型的当前状态。这完全取决于您选择如何实现它。
self.toJson = ko.computed(function(){
/*** Serialise self.items() and return the string ***/
return myJsonString;
});
接下来,将计算结果绑定(bind)到隐藏的输入,这将确保 View 模型在表单数据中持久化,从而允许您稍后重新水化 View 模型。
<input id="serialisedItems" type="hidden" data-bind="value: toJson" value="[1,4,3]" />
最后,在
$.ready()
上重新水化 View 模型以这种方式;$(function() {
var items = $('#serialisedItems').val();
/*** Deserialise items before passing into the List ***/
var list = new List(deserialisedItems);
ko.applyBindings(list);
});
在这一点上我还应该指出,列表已经通过设置
<input>
的 value 属性进行了初始化。 .
关于knockout.js - 使用 pjax 时在 history.back() 上消失的 knockout.js 绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17497946/