英文原版:https://guides.emberjs.com/v2.13.0/routing/redirection/
有些时候你会想要把用户从他们要访问的页面重定向到另一个页面。
比如,如果用户没有登录成功,你可能会想要阻止他们编辑个人的认证信息,资料或者查看购物车等。通常你会将用户重定向到登录页,并且仅在用户成功登录后,才允许用户访问那些页面。
Ember允许你通过路由中的钩子函数或方法控制这个交互过程。
其中一个方法就是transitionTo()。在路由中调用transitionTo()方法或者在控制器中调用transitionToRoute()方法会终止任何当前流程中的transitions并且开始一个新的transition,这些方法起到了重定向的作用。其中tansitionTo()的行为与{{link-to}}助手极为相似。
另一个方法是replaceWith(),它的作用跟transitionTo()方法一样。区别仅仅是replaceWith()方法会用重定向后的url替换掉历史记录中的重定向前的url,而transitionTo()方法会将重定向后的url添加到历史记录中。
如果路由中包含动态段,那么你需要给它传入一个model或者是标识符。若你传入model则不会触发model()钩子。
在Model()钩子被触发前重定向
由于路由的beforModel()钩子会在model()钩子之前被调用,所以这个方法是你做重定向的好地方。
app/router.js
Router.map(function() {
this.route('posts');
});
app/routes/index.js
import Ember from 'ember';
export default Ember.Route.extend({
beforeModel(/* transition */) {
this.transitionTo('posts'); // Implicitly aborts the on-going transition.
}
});
beforeModel()钩子接收当前的transition对象为参数,该对象可以被暂存并且可以在以后重新操作它。这使得我们有足够的操作间隙让用户返回到原先的路由去。比如,我们可以让试图访问信息编辑页并且登录不成功的用户返回到登录页,并且在他们登录成功后立即返回到信息编辑页面。阅读Storing nad Retrying a Transition章节来了解如何使用这个机制。
如果你想检查一些应用的状态以确定在什么时候需要重定向,那么你可能会需要service来帮你。
在Model()钩子被触发后重定向
如果你需要根据当前的模型数据来决定是否重定向,那么你可以使用afterModel()钩子。它接收模型数据为第一个参数,transition对象为第二个参数。
app/router.js
Router.map(function() {
this.route('posts');
this.route('post', { path: '/post/:post_id' });
});
app/routes/posts.js
import Ember from 'ember';
export default Ember.Route.extend({
afterModel(model, transition) {
if (model.get('length') === 1) {
this.transitionTo('post', model.get('firstObject'));
}
}
});
上例表明,当你访问posts路由时,如果它发现之后一个帖子,那么当前的transition会被终止,并且会重定向到post路由,同时会把这个model数据带过去。
子路由
改一下上面的路由,把它弄成嵌套路由:
app/router.js
Router.map(function() {
this.route('posts', function() {
this.route('post', { path: '/:post_id' });
});
});
如果我们在afterModel()中重定向到posts.post路由。本质上,afterModel()会使得本次transition失效。所以posts路由中的beforeModel(),model()和afterModel()会再次触发。
替代性的,我们可以使用redirect()方法,它可以使transition生效,并且不会再次触发父路由的钩子函数。
app/routes/posts.js
import Ember from 'ember';
export default Ember.Route.extend({
redirect(model, transition) {
if (model.get('length') === 1) {
this.transitionTo('posts.post', model.get('firstObject'));
)
};
本节完