解決vue重新整理頁面以後丟失store的資料問題
重新整理頁面時vue例項重新載入,store就會被重置,可以把定義重新整理前把store存入本地localStorage、sessionStorage、cookie中,localStorage是永久儲存,重新開啟頁面時會讀取上一次開啟的頁面資料,sessionStorage是儲存到關閉為止,cookie不適合存大量資料。根據我的需求,最合適的是sessionStorage。
beforeunload在頁面重新整理時觸發,可以監聽這個方法,讓頁面在重新整理前存store到sessionStorage中。
當然,在頁面重新整理時還要讀取sessionStorage中的資料到store中,讀取和儲存都寫在app.vue中。
export default { name: 'app',created () { // 在頁面載入時讀取sessionStorage if (sessionStorage.getItem('store')) { this.$store.replaceState(Object.assign({},this.$store.state,JSON.parse(sessionStorage.getItem('store')))) } // 在頁面重新整理時將store儲存到sessionStorage裡 window.addEventListener('beforeunload',() => { sessionStorage.setItem('store',JSON.stringify(this.$store.state)) }) } }
補充知識:vue專案將token存在(vuex)store和localstorage中
一、準備工作和token
1、準備工作
瞭解(session,cookie)token
Token的引入:Token是在客戶端頻繁向服務端請求資料,服務端頻繁的去資料庫查詢使用者名稱和密碼並進行對比,判斷使用者名稱和密碼正確與否,並作出相應提示,在這樣的背景下,Token便應運而生。
token 是在服務端產生的一串字串,以作客戶端進行請求的一個令牌。如果前端使用使用者名稱/密碼向服務端請求認證,服務端認證成功,那麼在服務端會返回 Token 給前端。前端可以在每次請求的時候帶上 Token 證明自己的合法地位。如果這個 Token 在服務端持久化(比如存入資料庫),那它就是一個永久的身份令牌(除非設定了有效期)。
token 優點
Token 完全由應用管理,所以它可以避開同源策略
Token 可以避免 CSRF 攻擊
Token 可以是無狀態的,可以在多個服務間共享
減輕伺服器的壓力,減少頻繁的查詢資料庫,使伺服器更加健壯。
安裝vuex
cnpm install vuex --save
2、介紹token用法
在前後端完全分離的情況下,Vue專案中實現token驗證大致思路如下:
1、第一次登入的時候,前端調後端的登陸介面,傳送使用者名稱和密碼
2、後端收到請求,驗證使用者名稱和密碼,驗證成功,就給前端返回一個token
3、前端拿到token,將token儲存到localStorage和vuex中,並跳轉路由頁面
4、前端每次跳轉路由,就判斷 localStroage 中有無 token ,沒有就跳轉到登入頁面,有則跳轉到對應路由頁面
5、每次調後端介面,都要在請求頭中加token
6、後端判斷請求頭中有無token,有token,就拿到token並驗證token,驗證成功就返回資料,驗證失敗(例如:token過期)就返回401,請求頭中沒有token也返回401
7、如果前端拿到狀態碼為401,就清除token資訊並跳轉到登入頁面
二、建立storage,store,request
1、src目錄:
注:建立storage是可選的,因為我把localstorage(快取)封裝到了storage.js(本文後續程式碼均是用自己封裝的js);建立store是必須的!
2、建立storage(可選)
// 封裝操作localstorage本地儲存的方法 模組化 var storage = { set(key,value) { localStorage.setItem(key,JSON.stringify(value)); // localStorage.key = value; // localStorage[key] = value; },get(key) { return JSON.parse(localStorage.getItem(key)); },getForIndex(index) { return localStorage.key(index); },getKeys(){ let items = this.getAll(); let keys = []; for (let index=0;index<items.length;index++){ keys.push(items[index].key); } return keys; },getLength() { return localStorage.length; },getSupport() { return (typeof (Storage) !== "undefined") ? true : false; },remove(key) { localStorage.removeItem(key); },removeAll() { localStorage.clear(); },getAll() { let len = localStorage.length; // 獲取長度 let arr = new Array(); // 定義資料集 for (var i = 0; i < len; i++) { // 獲取key 索引從0開始 var getKey = localStorage.key(i); // 獲取key對應的值 var getVal = localStorage.getItem(getKey); // 放進陣列 arr[i] = { 'key': getKey,'val': getVal,} } return arr; } } export default storage;
3、建立store
import Vue from 'vue' import Vuex from 'vuex' import storage from '@/model/storage' Vue.use(Vuex); // 用Vuex.Store物件用來記錄token const store = new Vuex.Store({ state: { // 儲存token // token: storage.get('token') ? storage.get('token') : '',token:"",userName:"" // 可選 },actions: { // removeToken: () => { // context.commit('set_token') // } },// 計算屬性 mutations: { // 修改token,並將token存入localStorage set_token(state,token) { state.token = token; storage.set('token',token); console.log('store、localstorage儲存token成功!'); },del_token(state) { state.token = ""; storage.remove("token"); },// 可選 setUserInfo(state,userName) { state.userName = userName; } } }); export default store;
4、建立request
import axios from 'axios' import store from '@/store' import router from '@/router' // create an axios instance const service = axios.create({ // index.js設定了代理(解決跨域) invoice = http://58.246.79.142:25005 baseURL: "/invoice",// url = base url + request url timeout: 5000,// request timeout } }) //新增請求攔截器,若token存在則在請求頭中加token,不存在也繼續請求 service.interceptors.request.use( config => { // 每次傳送請求之前檢測都vuex存有token,那麼都要放在請求頭髮送給伺服器,沒有則不帶token // Authorization是必須的 if (store.state.token) { config.headers.Authorization = store.state.token; } return config; },error => { console.log("在request攔截器顯示錯誤:",error.response) return Promise.reject(error); } ); //respone攔截器 service.interceptors.response.use( response => { // 在status正確的情況下,code不正確則返回對應的錯誤資訊(後臺自定義為200是正確,並且將錯誤資訊寫在message),正確則返回響應 return response.data.code == 200 ? response : Promise.reject(response.data.message); },error => { // 在status不正確的情況下,判別status狀態碼給出對應響應 if (error.response) { console.log("在respone攔截器顯示錯誤:",error.response) switch (error.response.status) { case 401: //可能是token過期,清除它 // this.$store.commit("del_token"); store.commit("del_token"); router.replace({ //跳轉到登入頁面 path: '/login',// 將跳轉的路由path作為引數,登入成功後跳轉到該路由 query: { redirect: router.currentRoute.fullPath } }); } } return Promise.reject(error.response.data); } ); export default service
三、配置代理,封裝路由router、設定路由守衛,在main.js中引入router
一、配置代理
二、封裝路由router,並設定路由守衛
/* eslint-disable */ import Vue from 'vue' import Router from 'vue-router' import Main from '@/main/index' import store from '@/store' import storage from '@/model/storage' Vue.use(Router) const routes = [ { path: '/',name: 'Main',redirect: '/login',// 某些頁面規定必須登入後才能檢視 ,可以在router中配置meta,將需要登入的requireAuth設為true, meta: { requireAuth: true,} },{ path: '/login',component: () => import('@/views/login'),},{ path: '/invoice',redirect: '/invoice',component: Main,] },{ path: '*',component: Main } ] const router = new Router({ routes: routes }) // 設定路由守衛,在進頁面之前,判斷有token,才進入頁面,否則返回登入頁面 if (storage.get("token")) { store.commit("set_token",storage.get("token")); } router.beforeEach((to,from,next) => { // 判斷要去的路由有沒有requiresAuth // to.matched.some(r => r.meta.requireAuth) or to.meta.requiresAuth if (to.matched.some(r => r.meta.requireAuth)) { if (store.state.token) { next(); //有token,進行request請求,後臺還會驗證token } else { next({ path: "/login",// 將剛剛要去的路由path(卻無許可權)作為引數,方便登入成功後直接跳轉到該路由,這要進一步在登陸頁面判斷 query: { redirect: to.fullPath } }); } } else { next(); //如果無需token,那麼隨它去吧 } }); export default router
三、在main.js中引入router
import Vue from 'vue' // import Vuex from 'vuex' import App from './App' import router from './router' import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css' // import VueResource from 'vue-resource' // import axios from 'axios' // 相容ie // import 'babel-polyfill'; Vue.use(ElementUI); // Vue.use(Vuex); // Vue.use(VueResource); // Vue.use(axios); Vue.config.productionTip = false Vue.component(CollapseTransition.name,CollapseTransition) // this.$ajax 全域性使用axios // Vue.prototype.$ajax=axios; new Vue({ el: '#app',router:router,components: { App },template: '<App/>' })
四、登入頁面實際使用
只給出表單提交示例函式和依賴js
import { postLogin } from "@/api/login"; submitForm(formName) { this.$refs[formName].validate(valid => { if (valid) { let that = this; // console.log('username',this.loginForm.username) // 通過校驗規則後進入校驗使用者名稱密碼是否正確 postLogin(this.loginForm.username,this.loginForm.password) .then(res => { console.log(res); that.$store.commit("set_token",res.data.token); that.$store.commit("setUserInfo",res.data.account); this.$notify({ title: "登入成功",type: "success",showClose: false,duration: 1000 }); setTimeout(() => { // 此時要判斷/login後面的引數,若無引數,進入主頁; this.$router.push("/index"); // 若有引數則引數為未有許可權的那個路由,跳轉到那個路由 // this.$router.push(***); -- 具體要自己在這實現 },1000); }) .catch(error => { // 錯誤分為 status-請求錯誤 和 code-賬號密碼錯誤 this.$message.error(error); console.log(error); }); } else { // 不符合前端校驗 this.$message.error('format error:'+error); console.log('format error:',error); return false; } }); }
上面依賴的@/api/login:
import request from '@/utils/request.js' export function postLogin(account,password) { console.log(account,password) return request({ url: '/login',method: 'post',params:{ // 具體傳參(鍵)要看後臺要求 account:account,password:password } }) }
以上這篇解決vue重新整理頁面以後丟失store的資料問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。