免责声明:我对 pager.js 一无所知,但我希望我的一般淘汰赛经验仍然可以提供帮助。
查看示例,page
绑定似乎使用来自 url 的初始值创建 observables。我的第一个直觉是扩展这个绑定并确保订阅每个这些值都会更新 URL。
让我们命名这个绑定twoway-page
:
ko.bindingHandlers["twoway-page"] = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// Call pager.js' page binding
ko.bindingHandlers.page.init(element, valueAccessor, allBindings, viewModel, bindingContext);
// ...
}
}
并在示例的绑定上调用它:
<div data-bind="twoway-page: {
id: 'start',
params: ['first','last']
}">
调用后page.init
,页面绑定扩展了视图模型,将params
数组中定义的可观察对象添加到viewModel
对象中。这意味着我们可以订阅这些 observables 的变化。
下一个挑战是计算正确的哈希。我查看了page-href
绑定如何计算其href
属性。原来它用于pager.page.path()
具有path
andparams
属性的对象。例如:
var hash = pager.page.path({
path: "user",
params: {
"first": "John",
"last": "Doe"
}
});
我试图在计算的 observable 中构造一个类似的对象。
// ...
var options = valueAccessor();
var pathObj = ko.computed(function() {
var result = {
path: options.id,
params: {}
};
options.params.forEach(function(param) {
result.params[param] = viewModel[param]();
});
return result;
}).extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } });
我找不到通过 pager.js 方法更新哈希的“干净”方法,但我确实注意到在内部,pagerjs 用于location.hash = "newhash"
设置一个值(尽管似乎也有一个 history/html5 替代方案......) . 无论如何,我们可以订阅我们的 observable 来更新哈希:
// ...
pathObj.subscribe(function(newValue) {
location.hash = pager.page.path(newValue);
});
现在,text
我们将使用textInput
绑定而不是示例中的绑定,以便我们可以更新值:
<div>
<span>First name:</span>
<input type="text" data-bind="textInput: first">
</div>
所以,总结一下:我最好的猜测是
- 扩展现有的 pager.js 绑定
- 在 URL 中创建对所有需要更新的 observable 的订阅
- 当值改变时自动更新哈希;使用
rateLimit
扩展来防止更新过载
使用位置哈希做一些事情有点难以在小提琴中展示,所以我记录了我的概念证明的 gif:

完整的自定义绑定代码为:
ko.bindingHandlers["twoway-page"] = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
ko.bindingHandlers.page.init(element, valueAccessor, allBindings, viewModel, bindingContext)
var options = valueAccessor();
var pathObj = ko.computed(function() {
var result = {
path: options.id,
params: {}
};
options.params.forEach(function(param) {
result.params[param] = viewModel[param]();
});
return result;
}).extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } });
pathObj.subscribe(function(newValue) {
location.hash = pager.page.path(newValue);
})
return { controlsDescendantBindings: true }
}
};