解决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 相关文章推荐
js 复制或插入Html的实现方法小结
May 19 Javascript
xml文档转换工具,附图表例子(hta)
Nov 17 Javascript
javascript等号运算符使用详解
Apr 16 Javascript
javascript动态创建链接的方法
May 13 Javascript
开启Javascript中apply、call、bind的用法之旅模式
Oct 28 Javascript
JS实现的驼峰式和连字符式转换功能分析
Dec 21 Javascript
Node.js的特点详解
Feb 03 Javascript
vue.js如何更改默认端口号8080为指定端口的方法
Jul 14 Javascript
JavaScript+CSS相册特效实例代码
Sep 07 Javascript
详解node+express+ejs+bootstrap构建项目
Sep 27 Javascript
jQuery响应滚动条事件功能示例
Oct 14 jQuery
layui获取选中行数据的实例讲解
Aug 19 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 实现进制转换(二进制、八进制、十六进制)互相转换实现代码
2010/10/22 PHP
使用ThinkPHP自带的Http类下载远程图片到本地的实现代码
2011/08/02 PHP
php异步多线程swoole用法实例
2014/11/14 PHP
Linux操作系统安装LAMP环境
2015/06/26 PHP
php变量与数组相互转换的方法(extract与compact)
2016/12/02 PHP
php实现简易计算器
2020/08/28 PHP
js实现的网站首页随机公告随机公告
2007/03/14 Javascript
10款非常有用的 Ajax 插件分享
2012/03/14 Javascript
javascript中setTimeout的问题解决方法
2014/05/08 Javascript
jquery实现可自动收缩的TAB网页选项卡代码
2015/09/06 Javascript
jQuery实现响应鼠标滚动的动感菜单效果
2015/09/21 Javascript
Jquery attr()方法 属性赋值和属性获取详解
2016/04/15 Javascript
js 求时间差的实现代码
2016/04/26 Javascript
深入理解JavaScript中的call、apply、bind方法的区别
2016/05/30 Javascript
JavaScript每天必学之数组和对象部分
2016/09/17 Javascript
Vue.js实现表格动态增加删除的方法(附源码下载)
2017/01/20 Javascript
vue v-model表单控件绑定详解
2017/05/17 Javascript
vue的全局提示框组件实例代码
2018/02/26 Javascript
Vue 自定义指令功能完整实例
2019/09/17 Javascript
element-ui table行点击获取行索引(index)并利用索引更换行顺序
2020/02/27 Javascript
[51:28]EG vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/16 DOTA
浅谈pyhton学习中出现的各种问题(新手必看)
2017/05/17 Python
CentOS7.3编译安装Python3.6.2的方法
2018/01/22 Python
python for和else语句趣谈
2019/07/02 Python
Python多线程Threading、子线程与守护线程实例详解
2020/03/24 Python
python dict乱码如何解决
2020/06/07 Python
详解如何解决H5开发使用wx.hideMenuItems无效果不生效
2021/01/20 HTML / CSS
教师个人自我鉴定
2014/02/08 职场文书
2014年毕业演讲稿范文
2014/05/13 职场文书
优秀班集体事迹材料
2014/12/25 职场文书
刮痧观后感
2015/06/05 职场文书
运动会观后感
2015/06/09 职场文书
春风化雨观后感
2015/06/11 职场文书
于丹讲座视频观后感
2015/06/15 职场文书
用python画城市轮播地图
2021/05/28 Python
Pandas 稀疏数据结构的实现
2021/07/25 Python