【问题标题】:Durandal: Multiple Routes, One ViewModel/ViewDurandal:多条路线,一个 ViewModel/View
【发布时间】:2013-05-14 02:20:27
【问题描述】:

我有 3 条路线:items/one、items/two 和 items/three,它们都指向“items”vm/view。

在 items.js 的激活函数中,我正在检查 url,并在此基础上更改过滤器:

function activate(r) {
        switch (r.routeInfo.url) {
            case 'items/one': vm.filterType(1); break;
            case 'items/two': vm.filterType(2); break;
            case 'items/three': vm.filterType(3); break;
        }
        return init(); //returns a promise
    }

项目视图有一个菜单,其中包含一、二和三的按钮。 每个按钮都链接到这样的操作:

function clickOne() {
    router.navigateTo('#/items/one');
}
function clickTwo() {
    router.navigateTo('#/items/two');
}    
function clickThree() {
    router.navigateTo('#/items/three');
}

这一切正常,我在视图上得到了正确的过滤器。但是,我注意到,如果我在“一”上,然后转到“二”,则 ko 绑定变量会“实时”更新,也就是说,随着它们的变化,在激活之前promise 解析,这会导致转换发生两次(在抓取数据时,以及在激活函数返回之后)。

这只发生在这种情况下,其中视图和视图模型与前一个相同。我知道这是一种特殊情况,路由器可能正在使用 areSameItem = true 处理新路由的加载。我可以将虚拟机/视图分成三个并尝试从基本模型继承,但我希望有一个更简单的解决方案。

【问题讨论】:

  • 它在调用你的activate 函数吗? filterType() 会返回承诺吗?
  • 当路由器导航到视图/虚拟机时,框架 (Durandal) 会自动调用激活函数。 filterType 只是一个带有整数值的 ko.observable。
  • 好的,所以当你设置filterType时会触发动画?是来自订阅者吗?您可能希望它成为 init() 的一部分,以便它返回的承诺适用于两种情况。

标签: durandal hottowel


【解决方案1】:

我可以通过在导航前对包含 div 的项目使用 ko.cleanNode() 删除 ko 绑定来解决此问题。

【讨论】:

  • 很高兴知道。下次遇到它时,我将不得不尝试。
  • 你在哪里调用 cleanNode?您是否必须重新添加绑定?
  • @Ely 我在router.navigateTo(...)之前调用了它,例如,如果我的div被称为items,我会调用var items = $('#items')[0]; ko.cleanNode(items);
【解决方案2】:

假设在您的父视图中,您使用 transition 引用了 router.activeItem,例如

<!--ko compose: {model: router.activeItem, 
    afterCompose: router.afterCompose, 
    transition: 'entrance'} -->
<!--/ko-->

然后入口转换发生在您设置以过滤当前视图的每条路线上。

但这种转换可能只发生在第一次访问时,从那时起,只有视图应该使用过滤后的数据进行更新。实现此目的的一种方法是设置一个可观察的filterType 并使用filterType.subscribe 调用带有skip 参数的router.navigateTo。

一些事情:

var filterType = ko.observable();

filterType.subscribe(function (val) {
    // Create an entry in the history but don't activate the new route to prevent transition
    // router plugin expects this without leading '/' dash.
    router.navigateTo(location.pathname.substring(1) + '#items/' + filterType(), 'skip');
    activate();
});

请注意,路由器插件需要 skipRouteUrl 而不带前导 / 斜杠来比较 context.path。 https://github.com/BlueSpire/Durandal/blob/master/App/durandal/plugins/router.js#L402

您的体验可能会有所不同。

最后为了支持activate中的深层链接:

function activate(routerdata) {
    // deep linking 
    if (routerdata && routerdata.filterType && (routerdata.filterType !== filterType() ) ) {
        filterType(routerdata.filterType);
    }

    return promise;
};

【讨论】:

  • 这行得通,但是正如你所说,过渡现在已经消失了,与应用程序的其余部分相比,这给了一个粗略的体验。有没有办法添加过渡效果(即使它纯粹是通过jquery)?我尝试在 KO 模板中使用 beforeRemove 和 afterAdd 绑定,但这些似乎不起作用。
  • 。例如var isFetching = ko.observable(false),您可以将其设置为 truein subscribe。在激活更改返回 init() 到 $.when(init()).then(function(){ self.isFetching(false)});
  • 下一次尝试:您可以考虑将var isFetching = ko.observable(false) 添加到您的VM。通过将其设置为truein subscribe,您可以确定动画的起点。在 activate 而不是返回承诺将其更改为 $.when(promise).then(function(){ ...}); 将允许您将其设置回 false。
  • 是的,这是一种很好的动画计时技术,但我可能只能显示一个动画加载图标,而不是所有项目同时淡入/滑入的整个视图过渡,就像在Durandal 的“入口”过渡。
  • 看起来这个“更简单”的替代方案有很多缺点,目前对于这个用例有用......至少在有人愿意深入研究视图转换之前。您可能会回到最初的想法,将其拆分为多个视图/虚拟机。
猜你喜欢
  • 1970-01-01
  • 2014-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
  • 1970-01-01
相关资源
最近更新 更多