在理解beforeEach無限循環以前,咱們先來看一下beforeEach相關的知識點,該篇文章的項目是基於 express+vue+mongodb+session實現註冊登陸 這篇文章項目基礎之上進行講解的,由於登陸完成後,會跳轉到列表頁面,那麼在跳轉到列表頁面以前,咱們會使用 router.js 使用beforeEach來判斷下,若是登陸成功,而且session在有效期內的話,就跳轉到下一個頁面去,不然的話,就重定向到登陸頁面去。
app/index/router.js 代碼以下:html
import Vue from 'vue'; import VueRouter from 'vue-router'; // 告訴 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/list', name: 'list', component: resolve => require(['./views/list'], resolve) }, { path: '*', // 其餘沒有的頁面都重定向到 home頁面去 redirect: '/login' }, { path: '/login', name: 'login', component: resolve => require(['./views/login'], resolve) }, { path: '/regist', name: 'regist', component: resolve => require(['./views/regist'], resolve) } ] var router = new VueRouter({ base: '/app/index', // 配置單頁應用的基路徑 routes: routes }); router.beforeEach((to, from, next) => { console.log(to); // 即將要進入路由的對象 console.log(from); // 當前導航要離開的路由對象 console.log(next); // 調用next該方法,才能進入下一個路由 next(); }); export default router;
如上代碼寫完成後,咱們從登陸頁面點擊登陸,登陸成功後,會跳轉至列表頁面。在跳轉以前會打印上面的信息。vue
console.log(to); 打印的信息以下:vue-router
console.log(from); 打印的信息以下:mongodb
如上代碼,調用 next()方法才能進入下一個路由,不然的若是寫了beforeEach方法,可是沒有調用next()方法的話,頁面會空白,不會跳轉到任何頁面的。默認不寫 router.beforeEach((to, from, next) => {}) 的話,它是默認跳轉到指定頁面去的,固然若是有這個方法的話,應該會覆蓋默認的方法。所以若是寫了調用了該方法的話,切記記得調用 next() 方法。express
next(false); 若是next方法添加一個false的話,那麼就會中斷當前的導航跳轉。修改完成後,咱們從新刷新 localhost:8081/list 這個頁面的話,會看到頁面一片空白,最後咱們打印下 console.log(to); 的信息以下:session
打印 console.log(from); 打印信息以下所示:app
next('/') 或者 next({ path: '/' }); 跳轉到一個不一樣的地址,當前的導航會被中段,而後會進入 path那個新的導航。post
如上是基本的beforeEach的語法,那麼在具體跳轉到那個頁面去,我想在beforeEach中判斷下,若是用戶登陸成功的話,而且session在有效期的話,那麼就跳轉到指定的頁面去,不然的話,就重定向到登陸頁面去。
先看登陸成功後的代碼以下:測試
this.$http.post('/reglogin/login', obj).then((res) => { if (res.body.code === 0) { // 登陸成功 const msg = res.body.msg || '登陸成功!!!'; localStorage.setItem('username', 1); this.messageFunc('success', msg); setTimeout(() => { this.$router.push({ path: '/list' }); }, 2000); } else { // 登陸失敗 const errorMsg = res.body.errorMsg || '登陸失敗'; this.messageFunc('warning', errorMsg); } });
登陸成功後,咱們會把 username 保存到 localStorage 中,咱們就能夠在 beforeEach中來判斷 localStorage 中是否有username了,固然若是登陸過時的話或者註銷的話,須要把本地存儲的 username該字段置爲null便可。ui
所以我router.js代碼會改爲以下所示:
router.beforeEach((to, from, next) => { console.log(localStorage.getItem('username')); if (localStorage.getItem('username') === null) { console.log('出現死循環了'); // 重定向到登陸頁面去 next({ path: '/login' }); } else { console.log('我是來測試的'); } });
如上代碼後會, 當咱們刷新下 http://localhost:8081/#/login 後會出現死循環,以下所示:
如上而且頁面是空白的,由於當咱們刷新 http://localhost:8081/#/login 後先會執行 router.beforeEach()該方法,由於咱們尚未登陸,因此獲取到本地存儲的username爲null,所以一直重定向到 /login 登陸頁面去,所以會一直出現死循環,按道理來講重定向到登陸頁面去的時候,頁面是登陸頁面,不該該是空白,可是有可能出現死循環了,致使一直重定向,最後什麼緣由致使空白了。
可是若是咱們改爲以下代碼就一切正常了,以下代碼:
router.beforeEach((to, from, next) => { /* console.log(localStorage.getItem('username')); if (localStorage.getItem('username') === null) { console.log('出現死循環了'); // 重定向到登陸頁面去 next({ path: '/login' }); } else { console.log('我是來測試的'); } */ if (true) { // 若是爲true的話,會重定向到指定頁面去,不然的話會重定向到登陸頁面去 next(); } else { next({ path: '/login' }); } });
如上代碼,我直接寫死了爲true,則直接調用 next()方法跳轉到下一個路由,就不會再調用 beforeEach()方法了。若是爲false的話,則跳轉到 登陸('/login') 頁面去。
所以爲了解決 全局 判斷用戶是否登陸跳轉的問題,咱們可使用以下方法解決:
router.beforeEach((to, from, next) => { if (localStorage.getItem('username')) { // 若是已經登陸的話 next(); } else { if (to.path === '/login') { // 若是是登陸頁面的話,直接next() next(); } else { // 不然 跳轉到登陸頁面 next({ path: '/login' }); } } });
固然在登陸接口中,登陸成功後,要使用 localStorage 保存用戶名,以下 app/index/views/login.vue 接口以下代碼:
this.$http.post('/reglogin/login', obj).then((res) => { if (res.body.code === 0) { // 登陸成功 const msg = res.body.msg || '登陸成功!!!'; // 這裏須要使用 localStorage 保存用戶名 localStorage.setItem('username', 1); this.messageFunc('success', msg); setTimeout(() => { this.$router.push({ path: '/list' }); }, 2000); } else { // 登陸失敗 const errorMsg = res.body.errorMsg || '登陸失敗'; this.messageFunc('warning', errorMsg); } });
固然 點擊註銷的時候 也要刪除該 username了,以下代碼:
// 註銷 logout() { this.$http.post('/reglogin/logout', {}).then((res) => { if (res.body.code === 1 && res.body.session) { // 說明註銷成功 跳轉到登陸頁面去 this.$message({ message: '註銷成功', type: 'success' }); localStorage.removeItem('username'); setTimeout(() => { this.$router.push({ path: '/login' }); }, 1000); } }); }
咱們首先看 beforeEach 代碼,
router.beforeEach((to, from, next) => { if (localStorage.getItem('username')) { // 若是已經登陸的話 next(); } else { if (to.path === '/login') { // 若是是登陸頁面的話,直接next() next(); } else { // 不然 跳轉到登陸頁面 next({ path: '/login' }); } } });
to 參數是到哪裏去的含義,所以當咱們刷新登陸頁面的時候,from 的值路徑爲 '/', to 的path爲 '/login', 所以調用next方法,仍是登陸頁面,不會出現死循環,和咱們上面講的以下代碼原理是同樣的:
router.beforeEach((to, from, next) => { if (true) { // 若是爲true的話,會重定向到指定頁面去,不然的話會重定向到登陸頁面去 next(); } else { next({ path: '/login' }); } });
而後當我登陸成功後,/login 接口會使用 localStorage 保存username信息,而後在跳轉頁面以前會繼續調用 beforeEach方法,而後會判斷:
if (localStorage.getItem('username')) { // 若是已經登陸的話 next(); }
說明有username的值,會執行下一個路由跳轉,所以能跳轉成功。