首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PagerJS如何与URL参数完成“双向绑定”?

PagerJS如何与URL参数完成“双向绑定”?
EN

Stack Overflow用户
提问于 2014-12-03 03:36:03
回答 2查看 693关注 0票数 10

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

代码语言:javascript
复制
<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>

这是一个单向绑定:如果可观察到的变化,由于用户在页面上的行动,URL将不会被更新。

在使用PagerJS时,建议如何保持URL参数与可观测值保持同步?

当然,我希望将用户动态创建的搜索条件存储在URL参数中,这是通过选择一组UI控件生成的,这样他/她就可以与其他人共享URL或书签了它,所有这些都不需要重新加载页面。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-06-02 20:40:25

免责声明:我不知道任何关于pager.js,但我希望我的一般淘汰赛经验仍然有帮助。

在这个例子中,page绑定似乎使用url中的初始值创建了可观察的值。我的第一反应是扩展这个绑定,并确保每个值的订阅都会更新URL。

让我们把这个绑定命名为twoway-page

代码语言:javascript
复制
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);

    // ...
  }
}

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

代码语言:javascript
复制
<div data-bind="twoway-page: {
                  id: 'start', 
                  params: ['first','last']
                 }">

调用page.init之后,页面绑定扩展了视图模型,将params数组中定义的可观察性添加到viewModel对象中。这意味着我们可以接受这些可观测数据的变化。

下一个挑战是计算正确的哈希。我查看了page-href绑定是如何计算其href属性的。结果表明,它在具有pathparams属性的对象上使用了params。例如:

代码语言:javascript
复制
var hash = pager.page.path({
  path: "user",
  params: {
    "first": "John",
    "last": "Doe"
  }
});

我试着在一个可观测的计算中构造一个类似的物体。

代码语言:javascript
复制
// ... 
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"来设置值(尽管似乎还有一个历史/html5 5选项.)。无论如何,我们可以订阅我们的可观察到的哈希更新:

代码语言:javascript
复制
// ...
pathObj.subscribe(function(newValue) {
    location.hash = pager.page.path(newValue);
});

现在,我们将使用text绑定来代替示例中的textInput绑定,这样我们就可以更新值:

代码语言:javascript
复制
<div>
  <span>First name:</span>
  <input type="text" data-bind="textInput: first">
</div>

所以,总结一下:我最好的猜测是

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

用位置散列做一些事情有点难以在小提琴中显示,所以我记录了我的概念证明:

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

代码语言:javascript
复制
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 }
    }
};
票数 5
EN

Stack Overflow用户

发布于 2017-02-16 11:14:54

我不能添加评论,所以我必须添加一个新的答案。user3297291的回答很好,它真的帮了我很多忙。然而,在现实世界中出现了一些问题,例如:

  1. 深度导航:页面,子页面,子页面等等options.id是不够的,我们需要完整的路径page/subpage/subsubpage (没有#!/ )
  2. 当页面间共享某些URL参数时,无论何时param发生变化,每个页面都会触发一个导航,最后一个页面将被显示出来。我在某些页面(productID等)之间共享相同的ID参数。

对于问题1,计算完整路径:

代码语言:javascript
复制
...var options = valueAccessor();
var parent = pager.getParentPage(bindingContext);
var fullroute = parent.getFullRoute()();
if(fullroute.length == 0) 
    var path = fullroute.join('/')+options.id;
else 
    var path = fullroute.join('/')+'/'+options.id;

result对象转化为:

代码语言:javascript
复制
var result = {
    path: path, 
    params: {}
};

对于问题2,我们必须告诉他们,只有当活动页面是他们自己的时,他们才能触发导航。

在订阅方法中,我们计算activePage路径并对它们进行比较:

代码语言:javascript
复制
pathObj.subscribe(function(newValue) {
    //calculate activePath
    var activeParent = pager.activePage$().parentPage.getFullRoute()();
    var activeId = pager.activePage$().getCurrentId();
    if(activeParent.length == 0)
        var activePath = activeParent .join('/')+activeId;
    else 
        var activePath = activeParent .join('/')+'/'+activeId;

    if( path == activePath ){
        location.hash = pager.page.path(newValue);
    }
})

此外,在循环抛出参数时,如果提供了默认值,则可以是数组或对象:

代码语言:javascript
复制
<div data-bind="page: {id: 'search', params: ['product','price']}" class="well">

需要:

代码语言:javascript
复制
options.params.forEach(function(param) {...

Vs

代码语言:javascript
复制
<div data-bind="page: {id: 'search', params: {'product': null,'price': 0}}" class="well">

需要这样的东西:

代码语言:javascript
复制
Object.keys(options.params).forEach(function(key,index) { 
    result.params[key] = viewModel[key](); 
}

再次感谢user3297291给出的答案,这真的是不同的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27263191

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档