解决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的数据问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
推荐阅读
-
解决vue单页使用keep-alive页面返回不刷新的问题
-
解决vue 路由变化页面数据不刷新的问题
-
使用sessionStorage解决vuex在页面刷新后数据被清除的问题
-
解决vue刷新页面以后丢失store的数据问题
-
解决使用Vue.js显示数据的时,页面闪现原始代码的问题
-
vuex结合session存储数据解决页面刷新数据丢失问题
-
解决Vue在封装了Axios后手动刷新页面拦截器无效的问题
-
持久化保存vuex数据-解决页面刷新后丢失vuex数据的问题
-
vue router嵌套路由在history模式下刷新无法渲染页面问题的解决方法
-
解决IE11 vue +webpack 项目中数据更新后页面没有刷新的问题