1

我想要一个#signin路由,它会在之前的任何页面顶部打开一个对话框。

让我们将这个示例应用程序视为以下路线:

router.map([
    {route: '', moduleId: 'vm/home', title: "Home"},
    {route: 'about', moduleId: 'vm/about', title: "About"},
    {route: 'signin', moduleId: 'vm/signin', title: 'Sign In'}
]);

以下是示例用例:

  1. 用户打开#并导航到:我们应该在主页顶部#signin看到一个登录对话框

  2. 用户打开#about并导航到:我们应该在“关于”页面顶部#signin看到一个登录对话框

  3. 用户导航到:我们应该在主页顶部http://localhost:9000/#signin看到一个登录对话框

  4. 用户打开#signin并关闭对话框:我们应该看到对话框后面的页面(后面总是有一个页面)。

4

3 回答 3

2

对话框和路由器都是插件,彼此之间没有交互。

还拥有路由器显示对话框会忽略路由器的工作方式 - 它有一个将内容转储到的 div。对话框存在于所有这些之外。

但是,如果你想(我也可以这样做),你可以试试这个。

添加dialog: true到路线图。

覆盖router.loadUrl方法。检查路由是否是我们之前标记的对话路由,然后激活对话。

我会将对话框设为子路由,这样您就可以知道在对话框下方显示哪个视图。否则,您可能只需要在任何内容上显示对话框并完全忽略路由。

编辑:我认为这实际上不会完全起作用。loadUrl返回一个布尔值。您可以打开对话框并返回 false 以取消导航。

编辑2:

我的尝试

loadUrl方法循环遍历所有路由,并且每个路由都有一个回调,因此理想情况下我们需要将我们的逻辑插入到这个数组中。

for (var i = 0; i < handlers.length; i++) {
    var current = handlers[i];
    if (current.routePattern.test(coreFragment)) {
        current.callback(coreFragment, queryString);
        return true;
    }
}

该数组是使用 routersroute方法添加的。当你映射路线时,Durandal 会调用这个方法,所以理想情况下,我们可以在路线配置中添加一些额外的参数,让 Durandal 处理这些。但是,该configureRoute功能是路由模块的内部功能,因此我们需要对其进行编辑,并确保在将来更新 Durandal 时复制更改。

我创建了一个新的对话路由列表:

{ route: 'taxcode/add(/:params)', moduleId: 'admin/taxcode/add', title: 'Add Tax Code', hash: '#taxcode/add', nav: false, dialog: true, owner: '#taxcodes' },
{ route: 'taxcode/edit/:id', moduleId: 'admin/taxcode/edit', title: 'Edit Tax Code', hash: '#taxcode/edit', nav: false, dialog: true, owner: '#taxcodes' }

所有者的想法是,如果存在初始路线是这样的情况,我们需要对话框后面的东西。

现在用这个替换router.route调用configureRoute

router.route(config.routePattern, function (fragment, queryString) {
    if (config.dialog) {
        if (!router.activeInstruction()) {
            // No current instruction, so load one to sit in the background (and go back to)
            var loadBackDrop = function (hash) {
                var backDropConfig = ko.utils.arrayFirst(router.routes, function (r) {
                    return r.hash == hash;
                });
                if (!backDropConfig) {
                    return false;
                }
                history.navigate(backDropConfig.hash, { trigger: false, replace: true });
                history.navigate(fragment, { trigger: false, replace: false });
                queueInstruction({
                    fragment: backDropConfig.hash,
                    queryString: "",
                    config: backDropConfig,
                    params: [],
                    queryParams: {}
                });
                return true;
            };

            if (typeof config.owner == 'string') {
                if (!loadBackDrop(config.owner)) {
                    delete config.owner;
                }
            }
            if (typeof config.owner != 'string') {
                 if (!loadBackDrop("")) {
                      router.navigate("");
                      return; // failed
                 }
            }
        }
        var navigatingAway = false;
        var subscription = router.activeInstruction.subscribe(function (newValue) {
            subscription.dispose();
            navigatingAway = true;
            system.acquire(config.moduleId).then(function (dialogInstance) {
                dialog.close(dialogInstance);
            });
        })
        // Have a route. Go back to it after dialog
        var paramInfo = createParams(config.routePattern, fragment, queryString);
        paramInfo.params.unshift(config.moduleId);
        dialog.show.apply(dialog, paramInfo.params)
            .always(function () {
                if (!navigatingAway) {
                    router.navigateBack();
                }
            });
    } else {
        var paramInfo = createParams(config.routePattern, fragment, queryString);
        queueInstruction({
            fragment: fragment,
            queryString: queryString,
            config: config,
            params: paramInfo.params,
            queryParams: paramInfo.queryParams
        });
    }
});

确保导入dialog到模块中。

于 2014-10-07T13:32:35.733 回答
1

好吧,当您对家庭视图模型的激活数据使用技巧时,可能不需要所有这些。看看我作为答案创建的Github 存储库。

这个想法是路由接受一个可选的激活数据,你的家庭虚拟机的激活方法可以检查并相应地显示所需的模式。

这种方式的好处是您根本不需要接触现有的 Durandal 插件或核心代码。我不确定这是否完全符合您的要求,因为要求没有详细说明。

更新:好的,我现在已经更新了 repo 以适应泛化的附加要求。本质上,现在我们在 shell 内利用 Durandal 的 Pub/Sub 机制,或者将其放置在您想要的任何其他位置。在那里,我们监听路由器 nav-complete 事件。当这种情况发生时,检查指令集并搜索给定的关键字。如果是这样,则触发模态。通过使用 navigation-complete 事件,我们还确保主 VM 正确且完全加载。对于您想要导航到#signin 的那些黑客,只需手动将它们重新路由到您想要的任何位置。

于 2014-10-11T07:39:56.063 回答
0

在评论中扩展我的建议,也许这样的事情会起作用。只需在或其他类似事件之一上配置事件挂钩router:route:activating并拦截/#signin. 然后使用这个钩子作为显示对话框的一种方式。请注意,此示例仅用于说明目的。我在工作时无法提供工作示例。:/我回家后可以完成,但至少这给了你一个想法。

router.on('router:route:activating').then(function (instance, instruction) {
  // TODO: Inspect the instruction for the sign in route, then show the sign in 
  // dialog and cancel route navigation.
});
于 2014-10-09T18:08:28.983 回答