解决vue刷新页面以后丢失store的数据问题


Posted in Javascript onAugust 11, 2020

刷新页面时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目录:

解决vue刷新页面以后丢失store的数据问题

注:创建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

一、配置代理

解决vue刷新页面以后丢失store的数据问题

二、封装路由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的数据问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript的Cookies
Jan 16 Javascript
cookie丢失问题(认证失效) Authentication (用户验证信息)也会丢失
Jun 04 Javascript
jquery 全局AJAX事件使用代码
Nov 05 Javascript
js实现俄罗斯方块小游戏分享
Jan 31 Javascript
基于JQuery实现仿网易邮箱全屏动感滚动插件fullPage
Sep 20 Javascript
JQuery遍历元素的后代和同胞实现方法
Sep 18 Javascript
react router 4.0以上的路由应用详解
Sep 21 Javascript
webstorm添加*.vue文件支持
May 08 Javascript
深入浅析js原型链和vue构造函数
Oct 25 Javascript
JavaScript 中 JSON.parse 函数 和 JSON.stringify 函数
Dec 05 Javascript
jQuery中使用validate插件校验表单功能
May 24 jQuery
vue组件库的在线主题编辑器的实现思路
Apr 03 Javascript
封装 axios+promise通用请求函数操作
Aug 11 #Javascript
在vue中使用回调函数,this调用无效的解决
Aug 11 #Javascript
vue 调用 RESTful风格接口操作
Aug 11 #Javascript
vue之封装多个组件调用同一接口的案例
Aug 11 #Javascript
vue接口请求加密实例
Aug 11 #Javascript
vue组件暴露和.js文件暴露接口操作
Aug 11 #Javascript
vue npm install 安装某个指定的版本操作
Aug 11 #Javascript
You might like
PHP连接MSSQL时nvarchar字段长度被截断为255的解决方法
2014/12/25 PHP
PHP 断点续传实例详解
2017/11/11 PHP
关于php支持的协议与封装协议总结(推荐)
2017/11/17 PHP
PHP code 验证码生成类定义和简单使用示例
2020/05/27 PHP
用javascript实现的激活输入框后隐藏初始内容
2007/06/29 Javascript
3种Jquery限制文本框只能输入数字字母的方法
2014/12/03 Javascript
基于jQuery实现Div窗口震动特效代码-代码简单
2015/08/28 Javascript
jQuery获取元素父节点的方法
2016/06/21 Javascript
详解Vue.js——60分钟组件快速入门(上篇)
2016/12/05 Javascript
JS实现发送短信验证后按钮倒计时功能(防止刷新倒计时失效)
2017/07/07 Javascript
jQuery中图片展示插件highslide.js的简单dom
2018/04/22 jQuery
JS浅拷贝和深拷贝原理与实现方法分析
2019/02/28 Javascript
Python中的集合类型知识讲解
2015/08/19 Python
Python实现列表转换成字典数据结构的方法
2016/03/11 Python
Python实现SSH远程登陆,并执行命令的方法(分享)
2017/05/08 Python
Python数据结构之双向链表的定义与使用方法示例
2018/01/16 Python
Python的SimpleHTTPServer模块用处及使用方法简介
2018/01/22 Python
python 将日期戳(五位数时间)转换为标准时间
2019/07/11 Python
Pycharm-community-2020.2.3 社区版安装教程图文详解
2020/12/08 Python
详解如何解决H5开发使用wx.hideMenuItems无效果不生效
2021/01/20 HTML / CSS
德国50岁以上交友网站:Lebensfreunde
2020/03/18 全球购物
夜大毕业生自我鉴定
2013/10/31 职场文书
会计电算化个人求职信范文
2014/01/24 职场文书
房地产活动策划方案
2014/05/14 职场文书
模具专业自荐信
2014/05/29 职场文书
淘宝活动总结范文
2014/06/26 职场文书
信用卡工资证明范本
2014/10/17 职场文书
清明节文明祭祀倡议书
2015/04/28 职场文书
2015年度学校卫生工作总结
2015/05/12 职场文书
在职证明格式样本
2015/06/15 职场文书
六五普法先进个人主要事迹材料
2015/11/03 职场文书
商务英语邮件开头问候语
2015/11/10 职场文书
2016幼儿园教师年度考核评语
2015/12/01 职场文书
2019年销售人员的职业生涯规划书
2019/03/25 职场文书
nginx proxy_cache 缓存配置详解
2021/03/31 Servers
7个关于Python的经典基础案例
2021/11/07 Python