解决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 相关文章推荐
caller和callee的区别介绍及演示结果
Mar 10 Javascript
window.event.keyCode兼容IE和Firefox实现js代码
May 30 Javascript
node.js中的fs.createReadStream方法使用说明
Dec 17 Javascript
Jquery promise实现一张一张加载图片
Nov 13 Javascript
jquery悬浮提示框完整实例
Jan 13 Javascript
JS SetInterval 代码实现页面轮询
Aug 11 Javascript
利用npm 安装删除模块的方法
May 15 Javascript
javascript显示动态时间的方法汇总
Jul 06 Javascript
JS实现的tab页切换效果完整示例
Dec 18 Javascript
微信小程序实现的日期午别医生排班表功能示例
Jan 09 Javascript
layui给下拉框、按钮状态、时间赋初始值的方法
Sep 10 Javascript
详解vue 自定义组件使用v-model 及探究其中原理
Oct 11 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
极典R601SW收音机
2021/03/02 无线电
给初学者的30条PHP最佳实践(荒野无灯)
2011/08/02 PHP
Laravel框架源码解析之反射的使用详解
2020/05/14 PHP
prototype 学习笔记整理
2009/07/17 Javascript
JavaScript 笔记二 Array和Date对象方法
2010/05/22 Javascript
使用jQuery.Validate进行客户端验证(初级篇) 不使用微软验证控件的理由
2010/06/28 Javascript
jquery提升性能最佳实践小结
2010/12/06 Javascript
JS Replace()的高级使用方法介绍
2013/06/29 Javascript
JavaScript学习笔记之Function对象
2015/01/22 Javascript
JavaScript中的DSL元编程介绍
2015/03/15 Javascript
第六篇Bootstrap表格样式介绍
2016/06/21 Javascript
jQuery表格的维护和删除操作
2017/02/03 Javascript
canvas实现探照灯效果
2017/02/07 Javascript
angular5 httpclient的示例实战
2018/03/12 Javascript
JS中的JSON对象的定义和取值实现代码
2018/05/09 Javascript
AngularJS自定义表单验证功能实例详解
2018/08/24 Javascript
在小程序Canvas中使用measureText的方法示例
2018/10/19 Javascript
对于防止按钮重复点击的尝试详解
2019/04/22 Javascript
基于js实现的图片拖拽排序源码实例
2020/11/04 Javascript
解决vue 使用axios.all()方法发起多个请求控制台报错的问题
2020/11/09 Javascript
基于python的汉字转GBK码实现代码
2012/02/19 Python
Python爬取国外天气预报网站的方法
2015/07/10 Python
Python实现多线程的两种方式分析
2018/08/29 Python
python读取word文档,插入mysql数据库的示例代码
2018/11/07 Python
python 爬取B站原视频的实例代码
2020/09/09 Python
python 30行代码实现蚂蚁森林自动偷能量
2021/02/08 Python
Html5 canvas实现粒子时钟的示例代码
2018/09/06 HTML / CSS
计算机专业大学生的自我评价
2013/11/14 职场文书
委托书范文
2014/04/02 职场文书
教你利用Selenium+python自动化来解决pip使用异常
2021/05/20 Python
vue-element-admin项目导入和导出的实现
2021/05/21 Vue.js
浅谈Python中的正则表达式
2021/06/28 Python
Java并发编程必备之Future机制
2021/06/30 Java/Android
spring cloud 配置中心客户端启动遇到的问题
2021/09/25 Java/Android
JavaWeb Servlet开发注册页面实例
2022/04/11 Java/Android
使用vuex-persistedstate本地存储vuex
2022/04/29 Vue.js