我很乐意使用 #signin 路线,该路线会在之前的任何页面上打开一个对话框。
让我们通过以下路线考虑这个示例应用程序:
router.map([
{route: '', moduleId: 'vm/home', title: "Home"},
{route: 'about', moduleId: 'vm/about', title: "About"},
{route: 'signin', moduleId: 'vm/signin', title: 'Sign In'}
]);
以下是示例用例:
用户在#
上并导航至#signin
:我们应该在主页页面<主页页面<上方看到登录对话框/ p>
用户在#about
上并导航至#signin
:我们应该会在关于页面<关于页面<上方看到登录对话框/ p>
用户导航至http://localhost:9000/#signin
:我们应该在主页页
用户在#signin
并关闭对话框:我们应该看到对话框后面的页面(后面总是有一页)。
答案 0 :(得分:2)
对话框和路由器都是插件,彼此之间没有交互。
同样具有路由器显示对话框将忽略路由器的工作方式 - 它有一个div,它将内容转储到。对话存在于所有这些之外。
但是如果你想(我也可以这样做),你可以试试这个。
将dialog: true
添加到路线图中。
覆盖router.loadUrl
方法。检查路线是否是我们之前标记的对话路线,然后改为激活对话框。
我会将对话框设置为子路径,这样您就可以知道在对话框下面显示哪个视图。否则你可能只需要显示任何对话框并完全忽略路由。
编辑:我不认为这实际上会完全奏效。 loadUrl
返回一个布尔值。您可以打开对话框并返回false以取消导航。
Edit2:
loadUrl
方法遍历所有路由,并且每个路由都有一个回调,所以理想情况下我们需要将逻辑插入到这个数组中。
for (var i = 0; i < handlers.length; i++) {
var current = handlers[i];
if (current.routePattern.test(coreFragment)) {
current.callback(coreFragment, queryString);
return true;
}
}
使用路由器route
方法添加此数组。 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
导入模块。
答案 1 :(得分:1)
当使用带有家庭视图模型的激活数据的技巧时,也许不需要所有这些。 看看我创建的Github repo作为答案。
这个想法是路由接受一个可选的激活数据,你的家庭虚拟机的激活方法可以检查并相应地显示所需的模态。
这样做的好处是您根本不需要触摸现有的Durandal插件或核心代码。 我不确定这是否完全符合您的要求,因为要求没有详细说明。
更新: 好的,我现在已经更新了repo以满足泛化的额外要求。基本上现在我们在shell中利用Durandal的Pub / Sub机制,或者将它放在你想要的任何地方。在那里我们听取路由器nav-complete事件。发生这种情况时,请检查指令集并搜索给定的关键字。如果是这样,那么就开始模态。通过使用导航完成事件,我们还确保主VM正确且完全加载。 对于那些想要导航到#signin的黑客,只需手动将它们重新路由到任何你想要的地方。
答案 2 :(得分: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.
});