解決vue刷新頁(yè)面以后丟失store的數(shù)據(jù)問題
刷新頁(yè)面時(shí)vue實(shí)例重新加載,store就會(huì)被重置,可以把定義刷新前把store存入本地localStorage、sessionStorage、cookie中,localStorage是永久儲(chǔ)存,重新打開頁(yè)面時(shí)會(huì)讀取上一次打開的頁(yè)面數(shù)據(jù),sessionStorage是儲(chǔ)存到關(guān)閉為止,cookie不適合存大量數(shù)據(jù)。根據(jù)我的需求,最合適的是sessionStorage。
beforeunload在頁(yè)面刷新時(shí)觸發(fā),可以監(jiān)聽這個(gè)方法,讓頁(yè)面在刷新前存store到sessionStorage中。
當(dāng)然,在頁(yè)面刷新時(shí)還要讀取sessionStorage中的數(shù)據(jù)到store中,讀取和儲(chǔ)存都寫在app.vue中。
export default { name: ’app’, created () { // 在頁(yè)面加載時(shí)讀取sessionStorage if (sessionStorage.getItem(’store’)) { this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem(’store’)))) } // 在頁(yè)面刷新時(shí)將store保存到sessionStorage里 window.addEventListener(’beforeunload’, () => { sessionStorage.setItem(’store’, JSON.stringify(this.$store.state)) }) }}
補(bǔ)充知識(shí):vue項(xiàng)目將token存在(vuex)store和localstorage中
一、準(zhǔn)備工作和token
1、準(zhǔn)備工作
了解(session,cookie)token
Token的引入:Token是在客戶端頻繁向服務(wù)端請(qǐng)求數(shù)據(jù),服務(wù)端頻繁的去數(shù)據(jù)庫(kù)查詢用戶名和密碼并進(jìn)行對(duì)比,判斷用戶名和密碼正確與否,并作出相應(yīng)提示,在這樣的背景下,Token便應(yīng)運(yùn)而生。
token 是在服務(wù)端產(chǎn)生的一串字符串,以作客戶端進(jìn)行請(qǐng)求的一個(gè)令牌。如果前端使用用戶名/密碼向服務(wù)端請(qǐng)求認(rèn)證,服務(wù)端認(rèn)證成功,那么在服務(wù)端會(huì)返回 Token 給前端。前端可以在每次請(qǐng)求的時(shí)候帶上 Token 證明自己的合法地位。如果這個(gè) Token 在服務(wù)端持久化(比如存入數(shù)據(jù)庫(kù)),那它就是一個(gè)永久的身份令牌(除非設(shè)置了有效期)。
token 優(yōu)點(diǎn)
Token 完全由應(yīng)用管理,所以它可以避開同源策略
Token 可以避免 CSRF 攻擊
Token 可以是無(wú)狀態(tài)的,可以在多個(gè)服務(wù)間共享
減輕服務(wù)器的壓力,減少頻繁的查詢數(shù)據(jù)庫(kù),使服務(wù)器更加健壯。
安裝vuex
cnpm install vuex --save
2、介紹token用法
在前后端完全分離的情況下,Vue項(xiàng)目中實(shí)現(xiàn)token驗(yàn)證大致思路如下:
1、第一次登錄的時(shí)候,前端調(diào)后端的登陸接口,發(fā)送用戶名和密碼
2、后端收到請(qǐng)求,驗(yàn)證用戶名和密碼,驗(yàn)證成功,就給前端返回一個(gè)token
3、前端拿到token,將token存儲(chǔ)到localStorage和vuex中,并跳轉(zhuǎn)路由頁(yè)面
4、前端每次跳轉(zhuǎn)路由,就判斷 localStroage 中有無(wú) token ,沒有就跳轉(zhuǎn)到登錄頁(yè)面,有則跳轉(zhuǎn)到對(duì)應(yīng)路由頁(yè)面
5、每次調(diào)后端接口,都要在請(qǐng)求頭中加token
6、后端判斷請(qǐng)求頭中有無(wú)token,有token,就拿到token并驗(yàn)證token,驗(yàn)證成功就返回?cái)?shù)據(jù),驗(yàn)證失敗(例如:token過期)就返回401,請(qǐng)求頭中沒有token也返回401
7、如果前端拿到狀態(tài)碼為401,就清除token信息并跳轉(zhuǎn)到登錄頁(yè)面
二、創(chuàng)建storage,store,request
1、src目錄:
注:創(chuàng)建storage是可選的,因?yàn)槲野裭ocalstorage(緩存)封裝到了storage.js(本文后續(xù)代碼均是用自己封裝的js);創(chuàng)建store是必須的!
2、創(chuàng)建storage(可選)
// 封裝操作localstorage本地存儲(chǔ)的方法 模塊化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; // 獲取長(zhǎng)度 let arr = new Array(); // 定義數(shù)據(jù)集 for (var i = 0; i < len; i++) { // 獲取key 索引從0開始 var getKey = localStorage.key(i); // 獲取key對(duì)應(yīng)的值 var getVal = localStorage.getItem(getKey); // 放進(jìn)數(shù)組 arr[i] = {’key’: getKey,’val’: getVal, } } return arr; }}export default storage;
3、創(chuàng)建store
import Vue from ’vue’import Vuex from ’vuex’import storage from ’@/model/storage’Vue.use(Vuex);// 用Vuex.Store對(duì)象用來(lái)記錄tokenconst store = new Vuex.Store({ state: { // 存儲(chǔ)token // token: storage.get(’token’) ? storage.get(’token’) : ’’, token:'', userName:'' // 可選 }, actions: { // removeToken: () => { // context.commit(’set_token’) // } }, // 計(jì)算屬性 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、創(chuàng)建request
import axios from ’axios’import store from ’@/store’import router from ’@/router’// create an axios instanceconst service = axios.create({ // index.js設(shè)置了代理(解決跨域) invoice = http://58.246.79.142:25005 baseURL: '/invoice', // url = base url + request url timeout: 5000, // request timeout }})//添加請(qǐng)求攔截器,若token存在則在請(qǐng)求頭中加token,不存在也繼續(xù)請(qǐng)求service.interceptors.request.use( config => { // 每次發(fā)送請(qǐng)求之前檢測(cè)都vuex存有token,那么都要放在請(qǐng)求頭發(fā)送給服務(wù)器,沒有則不帶token // Authorization是必須的 if (store.state.token) { config.headers.Authorization = store.state.token; } return config; }, error => { console.log('在request攔截器顯示錯(cuò)誤:', error.response) return Promise.reject(error); });//respone攔截器service.interceptors.response.use( response => { // 在status正確的情況下,code不正確則返回對(duì)應(yīng)的錯(cuò)誤信息(后臺(tái)自定義為200是正確,并且將錯(cuò)誤信息寫在message),正確則返回響應(yīng) return response.data.code == 200 ? response : Promise.reject(response.data.message); }, error => { // 在status不正確的情況下,判別status狀態(tài)碼給出對(duì)應(yīng)響應(yīng) if (error.response) { console.log('在respone攔截器顯示錯(cuò)誤:', error.response) switch (error.response.status) {case 401: //可能是token過期,清除它 // this.$store.commit('del_token'); store.commit('del_token'); router.replace({ //跳轉(zhuǎn)到登錄頁(yè)面 path: ’/login’, // 將跳轉(zhuǎn)的路由path作為參數(shù),登錄成功后跳轉(zhuǎn)到該路由 query: { redirect: router.currentRoute.fullPath } }); } } return Promise.reject(error.response.data); });export default service
三、配置代理,封裝路由router、設(shè)置路由守衛(wèi),在main.js中引入router
一、配置代理
二、封裝路由router,并設(shè)置路由守衛(wèi)
/* 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’, // 某些頁(yè)面規(guī)定必須登錄后才能查看 ,可以在router中配置meta,將需要登錄的requireAuth設(shè)為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 })// 設(shè)置路由守衛(wèi),在進(jìn)頁(yè)面之前,判斷有token,才進(jìn)入頁(yè)面,否則返回登錄頁(yè)面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,進(jìn)行request請(qǐng)求,后臺(tái)還會(huì)驗(yàn)證token } else { next({ path: '/login', // 將剛剛要去的路由path(卻無(wú)權(quán)限)作為參數(shù),方便登錄成功后直接跳轉(zhuǎn)到該路由,這要進(jìn)一步在登陸頁(yè)面判斷 query: { redirect: to.fullPath } }); } } else { next(); //如果無(wú)需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 = falseVue.component(CollapseTransition.name, CollapseTransition)// this.$ajax 全局使用axios// Vue.prototype.$ajax=axios;new Vue({ el: ’#app’, router:router, components: { App }, template: ’<App/>’})
四、登錄頁(yè)面實(shí)際使用
只給出表單提交示例函數(shù)和依賴js
import { postLogin } from '@/api/login';submitForm(formName) { this.$refs[formName].validate(valid => { if (valid) { let that = this; // console.log(’username’,this.loginForm.username) // 通過校驗(yàn)規(guī)則后進(jìn)入校驗(yàn)用戶名密碼是否正確 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(() => {// 此時(shí)要判斷/login后面的參數(shù),若無(wú)參數(shù),進(jìn)入主頁(yè);this.$router.push('/index');// 若有參數(shù)則參數(shù)為未有權(quán)限的那個(gè)路由,跳轉(zhuǎn)到那個(gè)路由// this.$router.push(***); -- 具體要自己在這實(shí)現(xiàn) }, 1000); }) .catch(error => { // 錯(cuò)誤分為 status-請(qǐng)求錯(cuò)誤 和 code-賬號(hào)密碼錯(cuò)誤 this.$message.error(error); console.log(error); }); } else { // 不符合前端校驗(yàn) 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:{ // 具體傳參(鍵)要看后臺(tái)要求 account:account, password:password } })}
以上這篇解決vue刷新頁(yè)面以后丟失store的數(shù)據(jù)問題就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。
相關(guān)文章:
1. ASP基礎(chǔ)入門第三篇(ASP腳本基礎(chǔ))2. PHP循環(huán)與分支知識(shí)點(diǎn)梳理3. 解析原生JS getComputedStyle4. 無(wú)線標(biāo)記語(yǔ)言(WML)基礎(chǔ)之WMLScript 基礎(chǔ)第1/2頁(yè)5. ASP刪除img標(biāo)簽的style屬性只保留src的正則函數(shù)6. ASP實(shí)現(xiàn)加法驗(yàn)證碼7. 讀大數(shù)據(jù)量的XML文件的讀取問題8. css代碼優(yōu)化的12個(gè)技巧9. 利用CSS3新特性創(chuàng)建透明邊框三角10. 前端從瀏覽器的渲染到性能優(yōu)化
