如下爲vue後臺管理項目中使用vuex的一點總結,截取了其中部分代碼,若有什麼錯誤,還望指出。javascript
登錄成功以後,須要把獲取到的 token 存儲到 vuex 中,配合 axios(或其餘 ajax 庫)的攔截器每次請求前加到 header 中傳給後臺。不過光放在 vuex 是不行的,由於考慮到瀏覽器會刷新,當用戶手動刷新了瀏覽器以後,vuex 中的狀態就會重置。因此當刷新頁面以後,因爲 token 丟失,後臺接收不到 token 會返回 401 到前臺,而前臺檢測到狀態 401 則會跳轉到登陸頁,因此每次刷新就會回到登陸每次刷新就會回到登陸。
/* state.js */ export default { get UserToken() { return sessionStorage.getItem("token"); }, set UserToken(value) { sessionStorage.setItem("token", value); } } /* mutation.js */ export default { LOGIN_IN(state, token){ state.UserToken = token; }, LOGIN_OUT(state){ state.UserToken = null; } } /* axios response攔截器 */ instance.interceptors.response.use(function (response) { return response.data; }, function (error) { if (error.response.status == 401){ Message({ type: "warning", message: "受權失敗,請從新登陸" }); store.commit("LOGIN_OUT"); router.replace({path: '/login'}) }else{ return Promise.reject(error); } });
能夠發現,這樣一來,雖然咱們從 vuex 中取數據,但實際上咱們操做的都是 sessionStorage。因爲 sessionStorage 在瀏覽器關閉以前都是有效的,即便是刷新了,仍是能從 sessionStorage 獲取到 token,從而防止了刷新回到登錄的問題。
登錄以後會從後臺獲取到當前用戶的權限數組,一樣的咱們也是存儲到 vuex 裏,不過這個就不須要什麼 get set 了,直接存就能夠了。
/* state.js */ export default { permissionList: null } /* menuNav.vue */ <template> <div class="navList"> <ul> <li v-for="item in permissionList">{{item.name}}</li> </ul> </div> </template> <script> export default { computed: { permissionList() { return this.$store.state.permissionList; } } } </script>
刷新後vuex存放的權限數組丟失;vue
用戶手動輸入地址進入沒有權限的路由,好比沒有 /admin 路由的用戶在瀏覽器修改了路由爲 /admin;java
對於第一個問題,能夠在每一個路由進入前判斷是否存在權限數組,ios
若是沒有:則去獲取;ajax
若是有:就進行第二個問題的判斷。vuex
爲此,咱們須要對在路由的配置時,標識路由是否須要權限,若是須要,而且當前用戶沒有權限,則不讓其進入。element-ui
因爲後臺返回的權限數組極可能是存在二級,三級,爲了方便用數組進行權限判斷,能夠配合store.getters,用遞歸的方式將其轉化爲一維數組並存到store.getters中,在進入每一個路由前經過Array.includes來判斷是否存在當前權限。axios
router.beforeEach((to, from, next) => { /* 判斷路由是否須要登陸,若是須要且無token回到登陸 */ if (to.matched.some(record => record.meta.requiresAuth)) { if (!store.state.UserToken) { next({ path: '/login' }) } else { /* 若是沒有權限列表先獲取 */ if (!store.state.permissionList) { store.dispatch("fetchPermissionList", next()); } else { var userAllPermission = store.getters.userAllPermission; /* 判斷是否存在*/ var isExist = userAllPermission.includes((item) => { return to.name==item.name }); /* 有當前路由的權限才進入,不然404 */ if (isExist) { next(); } else { next({path:'/404'}); } } } } else { /* 除了登陸頁,無需權限的均可進入 */ if(to.path!="/login"){ next(); }else{ /* 有token再也不進去登陸頁,回到以前的頁面 */ if(store.state.UserToken){ next(from.fullPath); } } } })
項目中一般會有一些各個頁面共用的數據,好比省份城市列表。爲了減小請求,城市都是等到點擊對應的省份時纔去獲取的。 相似這種東西,就能夠放到vuex中來維護,頁面都共享一份數據,這樣一來無疑能夠減小一些沒必要要的請求。不然,若是每一個頁面都存一份單獨的數據,假設A頁面請求了廣東省的城市,B,C頁面須要時,因爲每一個頁面的數據是單獨的,B,C又分別須要去請求一次。而放到vuex來維護,則只須要請求一次就能夠共享了。
/* state.js */ export default { province:[] } /* mutation */ export default { SET_PROVINCE(state, provincelist){ state.province = provincelist; } } /* action.js */ export default { /* 獲取全部省份 */ fetchProvinceList({ commit, state, }) { axios .get(`/cityRegions`) .then(res => { if (res.status == 0) { /* 組裝element-ui組件須要的格式 */ let province = res.data.map(item => { return { value: item.id, label: item.regionName, children: [] }; }); commit("SET_PROVINCE", province); } }) }, /* 獲取省份下的城市 */ fetchCityList({ commit, state, }, id) { /* 找到當前點擊的省份 */ var parent = state.province.find(item => { return item.value == id; }); /* 若是已經有子級城市就再也不請求 */ if (parent.children && parent.children.length <= 0) { axios .get(`/cityRegions?pId=${id}`) .then(res => { if (res.status == 0) { var city = res.data; city = city.map(item => { return { value: item.id, label: item.regionName }; }); parent.children = city.length > 0 ? city : null; } }) } } }