1. 程式人生 > >vuex實現登入狀態的儲存,未登入狀態不允許瀏覽

vuex實現登入狀態的儲存,未登入狀態不允許瀏覽

基礎思路就是使用vuex狀態管理來儲存登入狀態(其實就是存一個值,例如token),然後在路由跳轉前進行登入狀態的判斷,可以使用vue-router的全域性前置守衛beforeEach,也可以使用路由獨享的守衛beforeEnter。

導航守衛

正如其名,vue-router 提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程中:全域性的, 單個路由獨享的, 或者元件級的。
記住引數或查詢的改變並不會觸發進入/離開的導航守衛。你可以通過觀察 $route 物件來應對這些變化,或使用beforeRouteUpdate 的元件內守衛。

完整的導航解析流程

  1. 導航被觸發。
  2. 在失活的元件裡呼叫離開守衛。
  3. 呼叫全域性的 beforeEach 守衛。
  4. 在重用的元件裡呼叫 beforeRouteUpdate 守衛 (2.2+)。
  5. 在路由配置裡呼叫 beforeEnter。
  6. 解析非同步路由元件。
  7. 在被啟用的元件裡呼叫 beforeRouteEnter。
  8. 呼叫全域性的 beforeResolve 守衛 (2.5+)。
  9. 導航被確認。
  10. 呼叫全域性的 afterEach 鉤子。
  11. 觸發 DOM 更新。
  12. 用建立好的例項呼叫 beforeRouteEnter 守衛中傳給 next 的回撥函式。

全域性守衛

你可以使用 router.beforeEach註冊一個全域性前置守衛

const router = new VueRouter({ ...
}) router.beforeEach((to, from, next) => { // ... })

當一個導航觸發時,全域性前置守衛按照建立順序呼叫。守衛是非同步解析執行,此時導航在所有守衛 resolve 完之前一直處於 等待中。

每個守衛方法接收三個引數:

  • to: Route:即將要進入的目標 路由物件
  • from: Route:當前導航正要離開的路由
  • next: Function:一定要呼叫該方法來 resolve 這個鉤子。執行效果依賴 next 方法的呼叫引數。

next():進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。
next(false):

中斷當前的導航。如果瀏覽器的 URL 改變了(可能是使用者手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。
next('/')或者next({ path: '/' }): 跳轉到一個不同的地址。當前的導航被中斷,然後進行一個新的導航。
next(error):(2.4.0+) 如果傳入 next 的引數是一個 Error 例項,則導航會被終止且該錯誤會被傳遞給 router.onError()註冊過的回撥。
確保要呼叫 next 方法,否則鉤子就不會被 resolved。

路由獨享的守衛

你可以在路由配置上直接定義beforeEnter守衛:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

還有其他部分守衛,詳情可以看官方文件vue-router

安裝vuex後

建立store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state = {
    isLogin: 0
}

const mutations = {
    changeLogin(state,status){
        state.isLogin = status;
    }
}

const actions = {
    loginAction({commit}){
        commit('changeLogin',1);
    }
}

export default new Vuex.Store({
    state,
    actions,
    mutations
})

login.vue中

引入import { mapActions,mapState } from 'vuex'
接著進行登入狀態的改變,base_url就是路徑

export default {
        name: 'Login',
        data(){
            return{
                loginForm: {
                    username: '',
                    password: '',
                },
                rules: {
                    username: [
                        { required: true, message: '請輸入使用者名稱', trigger: 'blur' },
                    ],
                    password: [
                        { required: true, message: '請輸入密碼', trigger: 'blur' }
                    ],
                },
                showLogin: false
            }
        },
        mounted(){
            this.showLogin = true;
        },
        computed: {
            ...mapState(['isLogin'])
        },
        methods: {
            ...mapActions(['loginAction']),
            submitForm(formName){
                this.$refs[formName].validate((valid) => {
                    if(valid){
                        if(this.loginForm.username == 'aaa' && this.loginForm.password == '111'){
                            console.log('驗證通過');
                            this.loginAction();
                            this.$router.push('manage');
                        }else{
                            console.log('賬號密碼出錯');
                            // this.$message.error('賬號密碼出錯');
                            this.$message({
                                type: 'error',
                                message: '賬號密碼出錯'
                            });
                        }
                        console.log('請求地址: ' + base_url);
                    }else{
                        console.log('驗證失敗');
                        return false;
                    }
                })
            }
        }
    }

接下去只要使用路由守衛即可

beforeEach使用例項

router.beforeEach((to,from,next)=>{
    if(to.meta.check){
        var check = async function(){
            const result = await checkUser();
            if(result.status == 0){
                next();
            }else{
                alert('使用者未登入');
                next({path: '/login'});
            }
        }
        check();  //後臺驗證session
    }else{
        next();
    }
})

beforeEnter使用例項

export default new Router({
    routes: [
        {
          path: '/login',
          component: Login
        },
        {
            path: '/manage',
            name: '',
            component: Manage,
            beforeEnter: (to,from,next)=> {   //導航守衛
            console.log(to)
            console.log(from)
            if(store.state.isLogin == 1){
              console.log('使用者已經登入');
              next();
            }else{
              console.log('使用者未登入');
              next({path: '/login',query:{ Rurl: to.fullPath}});  //未登入則跳轉到登陸介面,query:{ Rurl: to.fullPath}表示把當前路由資訊傳遞過去方便登入後跳轉回來
          }
      } 
        }
     ]
})