英文原版: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'));
)
};
本節完