PagerJS如何使用URL params完成"双向绑定"?

Sla*_*mir 10 knockout.js pagerjs

PagerJS可以获取URL参数并将它们绑定到模型.例如,在本例来自PagerJS网站(参见链接)中,当您点击该链接时,它将导航到#/user?first=Philip&last=Fry并显示数据绑定子页面,显示"Philip Fry":

<a class="btn" data-bind="page-href: {path: 'user', params: {first: 'Philip', last: 'Fry'}}">Send parameter to page</a>

<div data-bind="page: {id: 'user', params: ['first','last']}" class="well-small">
    <div>
        <span>First name:</span>
        <span data-bind="text: first"></span>
    </div>
    <div>
        <span>Last name:</span>
        <span data-bind="text: last"></span>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

这是一种单向绑定:如果observable发生更改,由于页面上的用户操作,URL将不会更新.

使用PagerJS时,建议使用URL参数与observable同步的方法是什么?

我想在URL参数中存储用户动态创建的搜索条件(通过选择一组UI控件生成),这样他/她可以与其他人共享URL或将其加入书签,当然,所有这些都无需重新加载页面.

use*_*291 5

免责声明:我对pager.js一无所知,但我希望我的一般淘汰赛经验仍然有用.

查看示例,page绑定似乎使用url中的初始值创建了observable.我的第一直觉是扩展此绑定并确保订阅每个值都会更新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);

    // ...
  }
}
Run Code Online (Sandbox Code Playgroud)

并在示例的绑定上调用它:

<div data-bind="twoway-page: {
                  id: 'start', 
                  params: ['first','last']
                 }">
Run Code Online (Sandbox Code Playgroud)

调用之后page.init,页面绑定扩展了viewmodel,将params数组中定义的observable添加到viewModel对象中.这意味着我们可以订阅这些可观察量的变化.

下一个挑战是计算正确的哈希值.我查看了page-href绑定如何计算其href属性.原来它用于pager.page.path()具有pathparams属性的对象.例如:

var hash = pager.page.path({
  path: "user",
  params: {
    "first": "John",
    "last": "Doe"
  }
});
Run Code Online (Sandbox Code Playgroud)

我试图在计算的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" } });
Run Code Online (Sandbox Code Playgroud)

我找不到通过pager.js方法更新哈希的"干净"方法,但我注意到内部,pagerjs location.hash = "newhash"用来设置一个值(虽然似乎还有一个历史/ html5替代...) .无论如何,我们可以订阅我们的observable来更新哈希:

// ...
pathObj.subscribe(function(newValue) {
    location.hash = pager.page.path(newValue);
});
Run Code Online (Sandbox Code Playgroud)

现在,text我们将使用textInput绑定代替示例中的绑定,以便更新值:

<div>
  <span>First name:</span>
  <input type="text" data-bind="textInput: first">
</div>
Run Code Online (Sandbox Code Playgroud)

所以,结束:我最好的猜测是

  1. 扩展现有的pager.js绑定
  2. 创建对需要在URL中更新的所有可观察对象的订阅
  3. 值更改时自动更新哈希; 使用rateLimit扩展名来防止更新过载

使用位置哈希做一些东西有点难以在小提琴中显示,所以我记录了我的概念证明的gif:

使用自定义pagerjs绑定实时更新哈希

完整的自定义绑定代码是:

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 }
    }
};
Run Code Online (Sandbox Code Playgroud)